From 03dba08135a558147cce31990fb30e38ddd0b119 Mon Sep 17 00:00:00 2001 From: Zack Meier Date: Wed, 15 Apr 2026 15:42:41 -0500 Subject: [PATCH] sync --- ADO-PSRepo_ADOArtifact.ps1 | 4 + ActiveSyncDevices.ps1 | 43 + Add-CredentialToCsv.ps1 | 131 +++ Add-ManagerToDistributionGroup.ps1 | 49 + Add-VPNGroup.ps1 | 35 + AutoBuildTest.ps1 | 10 + AutomationJSON.ps1 | 8 + Azure-AddFileToStorageBlob.ps1 | 30 + Azure-PullTags.ps1 | 22 + Azure-VMHardwareReport.ps1 | 90 ++ Cohesity Loops.png | Bin 0 -> 210995 bytes Cohesity Loops.txt | 14 + Cohesity-AppNameSummary.ps1 | 25 + Cohesity-AppNamesWithSQL.ps1 | 47 + ...ableDisableProtectionGroupBasedOnCount.ps1 | 82 ++ Cohesity-NewBuildTracking.ps1 | 119 +++ Cohesity-ProtectionGroupsIndexing.ps1 | 29 + Cohesity-RemoteServiceChanges.ps1 | 25 + Cohesity-ServiceRunAs.ps1 | 21 + CohesityTests.ps1 | 28 + Copy-ITDRemoteFiles.ps1 | 6 + ESU-licensing-v3.1.ps1 | 82 ++ ESU-licensing.ps1 | 126 +++ ESU-servers.ps1 | 85 ++ Get-VMVRDatastores.ps1 | 21 + Get-Weather.ps1 | 12 + HPEILO-Certificates.ps1 | 74 ++ HelloWorld.ps1 | 3 + HomeDrive - Copy.ps1 | 57 ++ HomeDrive.bat | 1 + HomeDrive.ps1 | 37 + HomeDriveNoSign.ps1 | 24 + IIS-Logs.ps1 | 454 +++++++++ ITDAzHybridWorker.zip | Bin 0 -> 1800 bytes KMS-LicensingEventLog.ps1 | 48 + KMS-Office.ps1 | 28 + KMS-Windows.ps1 | 25 + Network-ConvertCIDRtoSubnetMask.ps1 | 45 + Network-VLANCompare.txt | 47 + PSObject with Properties.ps1 | 46 + PSRepo-Features.ps1 | 38 + PackageManagementInstall/Step1-CopyDll.ps1 | 8 + ...egPSRepo,InstallModules,CreateSchedule.ps1 | 3 + .../Step3-Install Modules.ps1 | 2 + .../Step4-ExpiredFilesDefaultConfig.ps1 | 2 + PasswordstateWinAPI.ps1 | 36 + Register-ADOPSRepo.ps1 | 8 + Remove-ITDTempFiles.ps1 | 11 + SCCM-AutomationDashboard.ps1 | 34 + SCCM-ESUDiscoveryY2.ps1 | 97 ++ SCCM-ESUDiscoveryY3.ps1 | 121 +++ SCCM-ESURemediationY2.ps1 | 68 ++ SCCM-ESURemediationY3.ps1 | 82 ++ SCCM-InstallUpdateViaSoftwareCenter.ps1 | 4 + SCCM-InstallUpdatesAndTrack.ps1 | 18 + SCCM-New Builds Last 2 Days Query.txt | 3 + SCCM-TSMUninstall.ps1 | 84 ++ SRMcom/SRM-Cmdlets-master.zip | Bin 0 -> 18819 bytes .../SRM-Cmdlets-master/.gitattributes | 1 + .../SRM-Cmdlets-master/.gitignore | 1 + .../Examples/ReportConfiguration.ps1 | 167 +++ .../Examples/SrmTagging.ps1 | 34 + .../SRM-Cmdlets-master/LICENSE.txt | 74 ++ .../Meadowcroft.Srm.Protection.ps1 | 422 ++++++++ .../Meadowcroft.Srm.Recovery.ps1 | 556 ++++++++++ .../Meadowcroft.Srm.Storage.ps1 | 24 + .../SRM-Cmdlets-master/Meadowcroft.Srm.psd1 | 92 ++ .../SRM-Cmdlets-master/Meadowcroft.Srm.psm1 | 148 +++ .../SRM-Cmdlets-master/NOTICE.txt | 7 + .../SRM-Cmdlets-master/README.md | 81 ++ ServiceNow-CHGRequest.ps1 | 33 + ServiceNow-GetRITM.ps1 | 65 ++ ServiceNow-GetRITMNDGOVUserId.ps1 | 10 + ServiceNow-GetRITMTaskAppServer.ps1 | 94 ++ ServiceNow-GetRITMTaskStorage.ps1 | 65 ++ ServiceNow-RitmDB.ps1 | 511 ++++++++++ ServiceNow-RitmDumpMK2.ps1 | 151 +++ Set-CohesityServiceSQL.ps1 | 21 + Set-ESULicensing.ps1 | 18 + SpotifyDownloader.ps1 | 20 + TranscriptData.ps1 | 58 ++ VM-AddToSolarwinds.ps1 | 14 + VMware-2403_coolingprep.ps1 | 74 ++ VMware-AutoBuildLoop.ps1 | 960 ++++++++++++++++++ VMware-AutoSnap.ps1 | 22 + VMware-BackupUplinksAndVMKernels.ps1 | 41 + VMware-DatastoreCapacity.ps1 | 31 + VMware-DisableAlarms.ps1 | 119 +++ VMware-DiskInventory.ps1 | 20 + VMware-EVC.ps1 | 21 + VMware-FixCoresPerSocket.ps1 | 20 + VMware-HA.ps1 | 16 + VMware-Host Network Config.ps1 | 20 + VMware-HostInventory.ps1 | 36 + VMware-HostInventoryV2.ps1 | 25 + VMware-HostTags.ps1 | 27 + VMware-IndPerDiskInfo.ps1 | 37 + VMware-LastPowerOnPowerOff.ps1 | 43 + VMware-ManualBackupViaClone.ps1 | 38 + VMware-ManualDisk.ps1 | 70 ++ VMware-ModuleList.ps1 | 9 + VMware-MoveToA9K.ps1 | 16 + VMware-MoveToFS9Bis.ps1 | 44 + VMware-MoveToFS9Mdn.ps1 | 53 + VMware-NewHostIPDNS.ps1 | 21 + VMware-NewHostWWPNs.ps1 | 33 + VMware-OfflineSnapshots.ps1 | 69 ++ VMware-OrphanedFilesOnDatastore.ps1 | 19 + VMware-PortGroupVMCount.ps1 | 43 + VMware-RemoveDatastores.ps1 | 23 + VMware-RunTCPDumpFromESX.txt | 1 + VMware-SQLVMsIndPerCheck.ps1 | 26 + VMware-ScratchLocations.ps1 | 28 + .../prod/ITD.VMware.Snapshots.Prod.psm1 | 484 +++++++++ .../rb-VMware-NewVMSnapshotTask-prdV3.ps1 | 34 + VMware-Stats.ps1 | 42 + VMware-TCPDump.ps1 | 2 + VMware-TPM.ps1 | 20 + VMware-TemplateUpdates.ps1 | 54 + VMware-VMPowerOffInfo.ps1 | 39 + VMware-VMToolsProductLocker.ps1 | 28 + VMware-VMToolsUpgrade.ps1 | 52 + VMware-VMToolsUpgradeAutoOnReboot.ps1 | 33 + VMware-vVolCount.ps1 | 8 + VMware-vVolsForTest.ps1 | 37 + WSL.ps1 | 13 + Windows-ESUDiscovery.ps1 | 97 ++ Windows-ESUDiscovery2012.ps1 | 83 ++ Windows-ESURemediation.ps1 | 68 ++ Windows-ESURemediation2012.ps1 | 31 + Windows-InstallAllMUUpdates.ps1 | 35 + Windows-PageFile.ps1 | 32 + Windows-SecurityLogStuff.ps1 | 29 + .../0.0.1/Private/Get-ZMPrivate.ps1 | 18 + .../0.0.1/Public/Get-ZMPublic.ps1 | 18 + .../0.0.1/Public/Get-ZMPublicAndPrivate.ps1 | 19 + ZM.ModuleExample/0.0.1/ZM.ModuleExample.psd1 | 132 +++ ZM.ModuleExample/0.0.1/ZM.ModuleExample.psm1 | 23 + ZMBackupLocalADORepo.ps1 | 28 + ZMBackupModules.ps1 | 48 + azure-pipelines.yml | 29 + backup-gpos.ps1 | 27 + gPLinkReport.ps1 | Bin 0 -> 32858 bytes iLOCertificatesAutoWithSectigo.ps1 | 227 +++++ pers cleanup.ps1 | 4 + readme.md | 2 +- 146 files changed, 9119 insertions(+), 1 deletion(-) create mode 100644 ADO-PSRepo_ADOArtifact.ps1 create mode 100644 ActiveSyncDevices.ps1 create mode 100644 Add-CredentialToCsv.ps1 create mode 100644 Add-ManagerToDistributionGroup.ps1 create mode 100644 Add-VPNGroup.ps1 create mode 100644 AutoBuildTest.ps1 create mode 100644 AutomationJSON.ps1 create mode 100644 Azure-AddFileToStorageBlob.ps1 create mode 100644 Azure-PullTags.ps1 create mode 100644 Azure-VMHardwareReport.ps1 create mode 100644 Cohesity Loops.png create mode 100644 Cohesity Loops.txt create mode 100644 Cohesity-AppNameSummary.ps1 create mode 100644 Cohesity-AppNamesWithSQL.ps1 create mode 100644 Cohesity-EnableDisableProtectionGroupBasedOnCount.ps1 create mode 100644 Cohesity-NewBuildTracking.ps1 create mode 100644 Cohesity-ProtectionGroupsIndexing.ps1 create mode 100644 Cohesity-RemoteServiceChanges.ps1 create mode 100644 Cohesity-ServiceRunAs.ps1 create mode 100644 CohesityTests.ps1 create mode 100644 Copy-ITDRemoteFiles.ps1 create mode 100644 ESU-licensing-v3.1.ps1 create mode 100644 ESU-licensing.ps1 create mode 100644 ESU-servers.ps1 create mode 100644 Get-VMVRDatastores.ps1 create mode 100644 Get-Weather.ps1 create mode 100644 HPEILO-Certificates.ps1 create mode 100644 HelloWorld.ps1 create mode 100644 HomeDrive - Copy.ps1 create mode 100644 HomeDrive.bat create mode 100644 HomeDrive.ps1 create mode 100644 HomeDriveNoSign.ps1 create mode 100644 IIS-Logs.ps1 create mode 100644 ITDAzHybridWorker.zip create mode 100644 KMS-LicensingEventLog.ps1 create mode 100644 KMS-Office.ps1 create mode 100644 KMS-Windows.ps1 create mode 100644 Network-ConvertCIDRtoSubnetMask.ps1 create mode 100644 Network-VLANCompare.txt create mode 100644 PSObject with Properties.ps1 create mode 100644 PSRepo-Features.ps1 create mode 100644 PackageManagementInstall/Step1-CopyDll.ps1 create mode 100644 PackageManagementInstall/Step2-RegPSRepo,InstallModules,CreateSchedule.ps1 create mode 100644 PackageManagementInstall/Step3-Install Modules.ps1 create mode 100644 PackageManagementInstall/Step4-ExpiredFilesDefaultConfig.ps1 create mode 100644 PasswordstateWinAPI.ps1 create mode 100644 Register-ADOPSRepo.ps1 create mode 100644 Remove-ITDTempFiles.ps1 create mode 100644 SCCM-AutomationDashboard.ps1 create mode 100644 SCCM-ESUDiscoveryY2.ps1 create mode 100644 SCCM-ESUDiscoveryY3.ps1 create mode 100644 SCCM-ESURemediationY2.ps1 create mode 100644 SCCM-ESURemediationY3.ps1 create mode 100644 SCCM-InstallUpdateViaSoftwareCenter.ps1 create mode 100644 SCCM-InstallUpdatesAndTrack.ps1 create mode 100644 SCCM-New Builds Last 2 Days Query.txt create mode 100644 SCCM-TSMUninstall.ps1 create mode 100644 SRMcom/SRM-Cmdlets-master.zip create mode 100644 SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/.gitattributes create mode 100644 SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/.gitignore create mode 100644 SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/Examples/ReportConfiguration.ps1 create mode 100644 SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/Examples/SrmTagging.ps1 create mode 100644 SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/LICENSE.txt create mode 100644 SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/Meadowcroft.Srm.Protection.ps1 create mode 100644 SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/Meadowcroft.Srm.Recovery.ps1 create mode 100644 SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/Meadowcroft.Srm.Storage.ps1 create mode 100644 SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/Meadowcroft.Srm.psd1 create mode 100644 SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/Meadowcroft.Srm.psm1 create mode 100644 SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/NOTICE.txt create mode 100644 SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/README.md create mode 100644 ServiceNow-CHGRequest.ps1 create mode 100644 ServiceNow-GetRITM.ps1 create mode 100644 ServiceNow-GetRITMNDGOVUserId.ps1 create mode 100644 ServiceNow-GetRITMTaskAppServer.ps1 create mode 100644 ServiceNow-GetRITMTaskStorage.ps1 create mode 100644 ServiceNow-RitmDB.ps1 create mode 100644 ServiceNow-RitmDumpMK2.ps1 create mode 100644 Set-CohesityServiceSQL.ps1 create mode 100644 Set-ESULicensing.ps1 create mode 100644 SpotifyDownloader.ps1 create mode 100644 TranscriptData.ps1 create mode 100644 VM-AddToSolarwinds.ps1 create mode 100644 VMware-2403_coolingprep.ps1 create mode 100644 VMware-AutoBuildLoop.ps1 create mode 100644 VMware-AutoSnap.ps1 create mode 100644 VMware-BackupUplinksAndVMKernels.ps1 create mode 100644 VMware-DatastoreCapacity.ps1 create mode 100644 VMware-DisableAlarms.ps1 create mode 100644 VMware-DiskInventory.ps1 create mode 100644 VMware-EVC.ps1 create mode 100644 VMware-FixCoresPerSocket.ps1 create mode 100644 VMware-HA.ps1 create mode 100644 VMware-Host Network Config.ps1 create mode 100644 VMware-HostInventory.ps1 create mode 100644 VMware-HostInventoryV2.ps1 create mode 100644 VMware-HostTags.ps1 create mode 100644 VMware-IndPerDiskInfo.ps1 create mode 100644 VMware-LastPowerOnPowerOff.ps1 create mode 100644 VMware-ManualBackupViaClone.ps1 create mode 100644 VMware-ManualDisk.ps1 create mode 100644 VMware-ModuleList.ps1 create mode 100644 VMware-MoveToA9K.ps1 create mode 100644 VMware-MoveToFS9Bis.ps1 create mode 100644 VMware-MoveToFS9Mdn.ps1 create mode 100644 VMware-NewHostIPDNS.ps1 create mode 100644 VMware-NewHostWWPNs.ps1 create mode 100644 VMware-OfflineSnapshots.ps1 create mode 100644 VMware-OrphanedFilesOnDatastore.ps1 create mode 100644 VMware-PortGroupVMCount.ps1 create mode 100644 VMware-RemoveDatastores.ps1 create mode 100644 VMware-RunTCPDumpFromESX.txt create mode 100644 VMware-SQLVMsIndPerCheck.ps1 create mode 100644 VMware-ScratchLocations.ps1 create mode 100644 VMware-SnapshotsV3/prod/ITD.VMware.Snapshots.Prod.psm1 create mode 100644 VMware-SnapshotsV3/prod/rb-VMware-NewVMSnapshotTask-prdV3.ps1 create mode 100644 VMware-Stats.ps1 create mode 100644 VMware-TCPDump.ps1 create mode 100644 VMware-TPM.ps1 create mode 100644 VMware-TemplateUpdates.ps1 create mode 100644 VMware-VMPowerOffInfo.ps1 create mode 100644 VMware-VMToolsProductLocker.ps1 create mode 100644 VMware-VMToolsUpgrade.ps1 create mode 100644 VMware-VMToolsUpgradeAutoOnReboot.ps1 create mode 100644 VMware-vVolCount.ps1 create mode 100644 VMware-vVolsForTest.ps1 create mode 100644 WSL.ps1 create mode 100644 Windows-ESUDiscovery.ps1 create mode 100644 Windows-ESUDiscovery2012.ps1 create mode 100644 Windows-ESURemediation.ps1 create mode 100644 Windows-ESURemediation2012.ps1 create mode 100644 Windows-InstallAllMUUpdates.ps1 create mode 100644 Windows-PageFile.ps1 create mode 100644 Windows-SecurityLogStuff.ps1 create mode 100644 ZM.ModuleExample/0.0.1/Private/Get-ZMPrivate.ps1 create mode 100644 ZM.ModuleExample/0.0.1/Public/Get-ZMPublic.ps1 create mode 100644 ZM.ModuleExample/0.0.1/Public/Get-ZMPublicAndPrivate.ps1 create mode 100644 ZM.ModuleExample/0.0.1/ZM.ModuleExample.psd1 create mode 100644 ZM.ModuleExample/0.0.1/ZM.ModuleExample.psm1 create mode 100644 ZMBackupLocalADORepo.ps1 create mode 100644 ZMBackupModules.ps1 create mode 100644 azure-pipelines.yml create mode 100644 backup-gpos.ps1 create mode 100644 gPLinkReport.ps1 create mode 100644 iLOCertificatesAutoWithSectigo.ps1 create mode 100644 pers cleanup.ps1 diff --git a/ADO-PSRepo_ADOArtifact.ps1 b/ADO-PSRepo_ADOArtifact.ps1 new file mode 100644 index 0000000..b7b00fe --- /dev/null +++ b/ADO-PSRepo_ADOArtifact.ps1 @@ -0,0 +1,4 @@ +# Register Ado Artifact Repo + +$url='https://pkgs.dev.azure.com/ndgov/_packaging/ITD3/nuget/v2' +Register-PSRepository -Name "NDGOV_ADO" -SourceLocation $url -PublishLocation $url -InstallationPolicy Trusted -Credential $AdoCred \ No newline at end of file diff --git a/ActiveSyncDevices.ps1 b/ActiveSyncDevices.ps1 new file mode 100644 index 0000000..a87b776 --- /dev/null +++ b/ActiveSyncDevices.ps1 @@ -0,0 +1,43 @@ +$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $M365Cred -Authentication Basic -AllowRedirection + +Import-PSSession $Session -DisableNameChecking + +## Get All Devices and Mailboxes metadata, store in memory/variable +## Torey should verify I'm pulling ActiveSync devices correctly: +#$AllDevices = Get-MobileDevice # All Devices +$AllDevices = Get-MobileDevice -ActiveSync # Only ActiveSync I hope +$AllMailboxes = Get-Mailbox -ResultSize Unlimited + +# Loop through each device, get a part of its identity, and match that identity part with a mailbox, 2400 devices took about 20 minutes to run +$result = @() +$count = 0 +ForEach ($Device in $AllDevices) { + $count++ + write-warning ($count.tostring() + '/' + $AllDevices.Count) + #clear loop variables + $Mailbox = $null + $DeviceDisplayName = $null + $ADUser = $null + + $DeviceDisplayName = $Device.Identity.split('\')[0] + $Mailbox = $AllMailboxes | Where-Object DisplayName -eq $DeviceDisplayName + If($Mailbox){ + $ADUser = Get-ADUser -Identity $Mailbox.PrimarySmtpAddress.split('@')[0] -Properties CanonicalName + } + + # create custom object to show only information we want + $obj = [PSCustomObject]@{ + DeviceDisplayName = $DeviceDisplayName; + DeviceAccessState = $Device.DeviceAccessState; + MailboxName = If($Mailbox){$Mailbox.Name}; + PrimarySmtpAddress = If($Mailbox){$Mailbox.PrimarySmtpAddress}; + Agency = If($Mailbox){$ADuser.CanonicalName.split('/')[1]}; + DeviceFriendlyName = $Device.FriendlyName; + DeviceUserAgent = $Device.DeviceUserAgent; + } + + # store new object in array + $result += $obj +} + +Write-Output $result \ No newline at end of file diff --git a/Add-CredentialToCsv.ps1 b/Add-CredentialToCsv.ps1 new file mode 100644 index 0000000..808064e --- /dev/null +++ b/Add-CredentialToCsv.ps1 @@ -0,0 +1,131 @@ + +<# +.Synopsis + Short description +.DESCRIPTION + Long description +.EXAMPLE + Example of how to use this cmdlet +.EXAMPLE + Another example of how to use this cmdlet +#> +function Add-ITDCredentialToCsv +{ + [CmdletBinding()] + Param + ( + [Parameter(Mandatory=$true)] + [string] + $VariableName + ) + + begin + { + + } + + process + { + + $NewCredential=Get-Credential + + $obj=[PSCustomObject]@{ + 'VariableName' = $VariableName + 'Username' = $NewCredential.UserName; + 'SecureString' = $NewCredential.Password | ConvertFrom-SecureString; + } + + + $Obj | export-csv ($env:USERPROFILE + "\Documents\accts.csv") -Force -Append + } + + end + { + } +} + +<# +.SYNOPSIS + Short description +.DESCRIPTION + Long description +.EXAMPLE + Example of how to use this cmdlet +.EXAMPLE + Another example of how to use this cmdlet +.INPUTS + Inputs to this cmdlet (if any) +.OUTPUTS + Output from this cmdlet (if any) +.NOTES + General notes +.COMPONENT + The component this cmdlet belongs to +.ROLE + The role this cmdlet belongs to +.FUNCTIONALITY + The functionality that best describes this cmdlet +#> +function Update-ITDCredentialCsv +{ + [CmdletBinding()] + Param + ( + [string[]] + $VariableName, + + [switch] + $All + ) + + begin + { + $csv = Import-Csv ($env:USERPROFILE + "\Documents\accts.csv") + } + + process + { + If($All) + { + $vn = $csv.VariableName + } + ForEach($vn in $VariableName) + { + $cred=$null + $cred = Get-Credential -Message ("Enter new credentials for variable named: " + $vn) + + If($Cred) + { + $csv = $csv | Where-Object VariableName -ne $vn | Export-Csv ($env:USERPROFILE + "\Documents\accts.csv") -Force + Add-ITDCredentialToCsv -VariableName $vn -Credential $cred + } + } + } + + end + { + } +} + +<# +.SYNOPSIS + Removes old versions of ITD modules +.DESCRIPTION + Long description +.EXAMPLE + Example of how to use this cmdlet +.EXAMPLE + Another example of how to use this cmdlet +.INPUTS + Inputs to this cmdlet (if any) +.OUTPUTS + Output from this cmdlet (if any) +.NOTES + General notes +.COMPONENT + The component this cmdlet belongs to +.ROLE + The role this cmdlet belongs to +.FUNCTIONALITY + The functionality that best describes this cmdlet +#> \ No newline at end of file diff --git a/Add-ManagerToDistributionGroup.ps1 b/Add-ManagerToDistributionGroup.ps1 new file mode 100644 index 0000000..fe26f46 --- /dev/null +++ b/Add-ManagerToDistributionGroup.ps1 @@ -0,0 +1,49 @@ +### fill in first three lines with csv path and distribution group names +$Import = Import-Csv 'D:\Downloads\nd-all-managers.csv' -Header DeptNum,CAPSUPN,UPN,Name,Cabinet +$AllStateGroupName = '' +$CabinetGroupName = '' + + +$AllStateGroup = Get-DistributionGroup -Identity $AllStateGroupName +$AllStateGroupMembers = $AllStateGroup | Get-DistributionGroupMember + +$CabinetGroup = Get-DistributionGroup -Identity $CabinetGroupName +$CabinetGroupMembers = $CabinetGroup | Get-DistributionGroupMember + + + +$CompareAllState = Compare-Object -ReferenceObject $Import -DifferenceObject $AllStateGroupMembers -IncludeEqual +# <= Add to Group +# == No change +# => Remove from group +$AllStateUsersToAdd = $Compare | Where-Object SideIndicator -eq '<=' +$AllStateUsersToRemove = $Compare | Where-Object SideIndicator -eq '=>' + +ForEach($User in $AllStateUsersToAdd) +{ + Add-DistributionGroupMember -Identity $AllStateGroupName -Member $User +} + +ForEach($User in $AllStateUsersToRemove) +{ + Remove-DistributionGroupMember -Identity $AllStateGroupName -Member $User +} + + +$CompareCabinetManagers = Compare-Object -ReferenceObject ($Import | Where-Object Cabinet -eq 'Y') -DifferenceObject $CabinetGroupMembers -IncludeEqual +# <= Add to Group +# == No change +# => Remove from group +$CabinetUsersToAdd = $Compare | Where-Object SideIndicator -eq '<=' +$CabinetUsersToRemove = $Compare | Where-Object SideIndicator -eq '=>' + +ForEach($User in $CabinetUsersToAdd) +{ + Add-DistributionGroupMember -Identity $CabinetGroupName -Member $User +} + + +ForEach($User in $CabinetUsersToRemove) +{ + Remove-DistributionGroupMember -Identity $CabinetGroupName -Member $User +} diff --git a/Add-VPNGroup.ps1 b/Add-VPNGroup.ps1 new file mode 100644 index 0000000..b110d93 --- /dev/null +++ b/Add-VPNGroup.ps1 @@ -0,0 +1,35 @@ +$M365Groups = Get-ADGroup -Filter {Name -like "*-O365-E3"} +#$VPNGroups = Get-ADGroup -Filter {Name -like "*VPN*"} + +$UsersToAdd=@() +[int]$TotalUsers=0 + +ForEach($M365Group in $M365Groups) +{ + $user = $null + $users = $null + + $Users = Get-ADGroupMember -Identity $M365Group.SamAccountName + $TotalUsers += $Users.count + $AllUsers += $Users + + Write-Warning -Message ([string](Get-Date) + " Group: " + $M365Group.SamAccountName) + Write-Warning -Message ([string](Get-Date) + " User count " + $Users.count) + + Foreach($User in $Users) + { + $ADUser = Get-ADUser -Identity $User -Properties EmailAddress,Company,Department,CanonicalName + $UserMemberOf = (Get-ADUser -Identity $User -Properties MemberOf).MemberOf | Sort-Object + $UserMemberOfVPN = $UserMemberOf | Where-Object {$_ -like "*VPN*"} + If(@($UserMemberOfVPN).count -eq 0) + { + $UsersToAdd += $ADUser + } + } + Write-Warning -Message ([string](Get-Date) + " UsersToAdd Total count " + $UsersToAdd.count) +} + +$UsersToAdd | Export-Csv D:\UsersToAdd.csv + +#Add-ADGroupMember -Identity ITD-COVID19-SSLVPN -Members $UsersToAdd -Credential $AdminCred +Add-ADGroupMember -Identity ITD-COVID19-SSLVPN -Members (Import-Csv D:\UsersToAdd-Enabled.csv).SamAccountName -Credential $AdminCred \ No newline at end of file diff --git a/AutoBuildTest.ps1 b/AutoBuildTest.ps1 new file mode 100644 index 0000000..cafd2df --- /dev/null +++ b/AutoBuildTest.ps1 @@ -0,0 +1,10 @@ +# Write your PowerShell commands here. + +Write-Host "##vso[task.setvariable variable=Hostname]deploy002" +Write-Host "##vso[task.setvariable variable=IpAddress]192.168.99.99" +Write-Host "##vso[task.setvariable variable=IpAddress]255.255.255.0" +Write-Host "##vso[task.setvariable variable=IpAddress]192.168.99.1" + +HPE_Synergy_Composer_2_6.00.00_UPDATE_Z7550-97071.bin +69321351ad32a401ad3cd6f5b1d715a2c984f7c077e57afe7acd3d527a7cc3ce +69321351ad32a401ad3cd6f5b1d715a2c984f7c077e57afe7acd3d527a7cc3ce \ No newline at end of file diff --git a/AutomationJSON.ps1 b/AutomationJSON.ps1 new file mode 100644 index 0000000..e962cc2 --- /dev/null +++ b/AutomationJSON.ps1 @@ -0,0 +1,8 @@ +$postParams = [PSCustomObject]@{ + AutomationName = "Infra-VMware"; + Action = 'Provisioning'; + Units = 5; + Platform = 'PowerShell-VMware-SnapshotNew'; +} + +Invoke-RestMethod -Uri http://itdnettools.nd.gov/services/automation-tracking.py -Method POST -Body ($postParams | ConvertTo-Json) \ No newline at end of file diff --git a/Azure-AddFileToStorageBlob.ps1 b/Azure-AddFileToStorageBlob.ps1 new file mode 100644 index 0000000..a41cdee --- /dev/null +++ b/Azure-AddFileToStorageBlob.ps1 @@ -0,0 +1,30 @@ +$acctkey="m1baKn6kkg5fL/wJzHFrDq28LmDCK0ylVXj9bWCJxW/JwJ6or03Qska4jZPpVAC63Tt19i254pvrY8sqI8iKCA==" +#DefaultEndpointsProtocol=https;AccountName=sazmeiersharedm365;AccountKey=m1baKn6kkg5fL/wJzHFrDq28LmDCK0ylVXj9bWCJxW/JwJ6or03Qska4jZPpVAC63Tt19i254pvrY8sqI8iKCA==;EndpointSuffix=core.windows.net + +$storageContext = New-AzureStorageContext -StorageAccountName 'sazmeiersharedm365' -StorageAccountKey $acctkey + +$LogFull = "zmtestfile01.log" +$LogItem = New-Item -ItemType File -Name $LogFull -force + +Set-AzureStorageBlobContent -File $LogFull -Container "azuretest" -BlobType Block -Context $storageContext -Verbose + + + +$AllTeams = Get-Team +$AllTeams | export-csv "C:\users\zmeier\desktop\filetest03.csv" +Set-AzureStorageBlobContent -File "filetest03.csv" -Container "azuretest" -BlobType Block -Context $storageContext + + + +<# In runbook: +$svcitdm365auto = Get-AutomationPSCredential -Name 'Microsoft365 Auto' +Connect-MicrosoftTeams -Credential $svcitdm365auto +$acctkey = (Get-AutomationPSCredential -Name 'Azure-sazmeiersharedm365').GetNetworkCredential().Password +$storageContext = New-AzureStorageContext -StorageAccountName 'sazmeiersharedm365' -StorageAccountKey $acctkey +#$LogName = "zmtestfile02.log" +#$LogItem = New-Item -ItemType File -Name $LogName +#Set-AzureStorageBlobContent -File $LogName -Container "azuretest" -BlobType Block -Context $storageContext -Verbose + +$AllTeams = Get-Team +$AllTeams | export-csv "$env:TEMP\filetest03.csv" -notypeinformation +Set-AzureStorageBlobContent -File "$env:TEMP\filetest03.csv" -Container "azuretest" -BlobType Block -Context $storageContext#> \ No newline at end of file diff --git a/Azure-PullTags.ps1 b/Azure-PullTags.ps1 new file mode 100644 index 0000000..f236cff --- /dev/null +++ b/Azure-PullTags.ps1 @@ -0,0 +1,22 @@ +$AllWebApps = Get-AzureRMWebApp + +$result = @() +ForEach($app in $AllWebApps) +{ + $hash = @{ + 'Name' = $app.Name; + 'Location' = $app.Location; + } + + $Tags = $app.tags + ForEach($TagKey in $Tags.Keys) + { + $hash += @{$TagKey = $Tags.$TagKey} + } + + $obj = New-Object -TypeName psobject -Property $hash + + $result += $obj +} + +$result \ No newline at end of file diff --git a/Azure-VMHardwareReport.ps1 b/Azure-VMHardwareReport.ps1 new file mode 100644 index 0000000..59d3470 --- /dev/null +++ b/Azure-VMHardwareReport.ps1 @@ -0,0 +1,90 @@ +$Subscriptions = Get-AzSubscription + +$AzureVMs = [System.Collections.ArrayList]@() +ForEach ($Subscription in $Subscriptions) { + Set-AzContext -Subscription $Subscription + + $AllVMs = Get-AzVM + + ForEach ($VM in $AllVMs) { + $VMSize = $null + $VMSizeSpecs = $null + $OSDisk = $null + $DataDisks = $null + $obj = $null + + $VMSize = $VM.HardwareProfile.VMSize + $VMSizeSpecs = Get-AzVMSize -Location $VM.Location | Where-Object { $_.Name -eq $VMSize } + + $OSDisk = $VM.StorageProfile.OSDisk + $DataDisks = $VM.StorageProfile.DataDisks + + #$IpAddress = (Get-AzNetworkInterface | Where-Object {$_.Id -eq $VM.NetworkProfile.NetworkInterfaces.Id}).IpConfigurations.PrivateIpAddress + + $obj = [PSCustomObject]@{ + VMName = $VM.Name + Subscription = $Subscription.Name + ComputerName = $VM.OSProfile.ComputerName + Size = $VMSize + CPU = $VMSizeSpecs.NumberOfCores + Memory = ($VMSizeSpecs.MemoryInMb / 1024) + TotalDisk = ($OSDisk.DiskSizeGB + ($DataDisks.DiskSizeGB | Measure-Object -Sum).Sum) + OsDiskGB = $OSDisk.DiskSizeGB + DataDisksGB = $DataDisks.DiskSizeGB -join ", " + } + + $null = $AzureVMs.Add($obj) + } +} + +$SharePointList = Get-ITDVMwareSharePointVMGuestList | Where-Object { $_.Status -notlike "D*" -and ($_.DataCenter -like "MAC*" -or $_.DataCenter -like "MAG*") } + +$AzureToSharePointCompare = [System.Collections.ArrayList]@() + +ForEach ($AzVM in $AzureVMs) { + $SPItem = $null + + Write-Verbose -Message ("Start " + $AzVM.VMName) -Verbose + + $SPItem = $SharePointList | Where-Object { $_.Title -match $AzVM.VMName.split('-')[1] } + Write-Verbose -Message ("Found " + $SPItem.Count + " possible SharePoint matches") -Verbose + + $obj = [PSCustomObject]@{ + AzVMName = $AzVM.VMName; + #AzComputerName = $AzVM.ComputerName + SPTitle = $SPItem.Title; + CPU = $null; + MemoryGB = $null; + DiskTotal = $null; + } + + + Write-Verbose -Message "One match found, starting compare" + + If ($SPItem.Processors -ne $AzVM.CPU) { + $obj.CPU = $false + } + Else { + $obj.CPU = $true + } + + If ($SPItem.RAM -ne $AzVM.Memory) { + $obj.MemoryGB = $false + } + Else { + $obj.MemoryGB = $true + } + + $SPDiskTotalGB = $SPItem.Disk1 + $SPItem.Disk2 + $SPItem.Disk3 + $SPItem.Disk4 + If ($SPDiskTotalGB -ne $AzVM.TotalDisk) { + $obj.DiskTotal = $false + } + Else { + $obj.DiskTotal = $true + } + + $null = $AzureToSharePointCompare.Add($obj) + + +} + diff --git a/Cohesity Loops.png b/Cohesity Loops.png new file mode 100644 index 0000000000000000000000000000000000000000..48f7adba965fcff452937d9d20f4a7c152c398ad GIT binary patch literal 210995 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�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 Pz)L|!Rk}>lH2A*&f+x0d literal 0 HcmV?d00001 diff --git a/Cohesity Loops.txt b/Cohesity Loops.txt new file mode 100644 index 0000000..e46fd47 --- /dev/null +++ b/Cohesity Loops.txt @@ -0,0 +1,14 @@ +for node in 01 02 03 04 05 06 07 08 09 10 +do ssh -i ~cecogdill/.ssh/id_rsa_itdmdndpc01 support@itdmdndpc01n$node.nd.gov "sudo timeout 180 tcpdump -C 200 -i br0.3895 -s 65535 -w pcap.out '(src net 10.2.170.0/24 or src net 10.2.169.128/26)' and '(dst net 10.2.169.128/26 or dst net 10.2.170.0/24)' and src net not 10.29.0.0/23 and port not 22 &" +done + + + +for node in 01 02 03 04 05 06 07 08 09 10 +do ssh -i ~cecogdill/.ssh/id_rsa_itdmdndpc01 support@itdmdndpc01n$node.nd.gov "sudo pkill timeout" +done + + + + +for host in `ls`; do cd $host; ssh -i ~cecogdill/.ssh/id_rsa_itdmdndpc01 support@$host.nd.gov 'rm pcap.out*'; done \ No newline at end of file diff --git a/Cohesity-AppNameSummary.ps1 b/Cohesity-AppNameSummary.ps1 new file mode 100644 index 0000000..01309d7 --- /dev/null +++ b/Cohesity-AppNameSummary.ps1 @@ -0,0 +1,25 @@ +$AllVMs = Get-VM | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" } +#$DataProtectionVMs = (Get-TagAssignment -Category DataProtection).Entity | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" } +$result = [System.Collections.ArrayList]@() +ForEach ($VM in $AllVMs) { + $AppName = ($VM | Get-TagAssignment -Category AppName).Tag.Name; + $CohesityGB = (($VM | Get-harddisk) | Measure-object -sum CapacityGB).sum; + #$AppTotalGB = ($AllVMs | Get-TagAssignment -Category AppName | Where-object Name -eq $AppName); + $OldTag = ($VM | Get-TagAssignment -Category DataProtection).Tag.Name + $vCenter = $VM.Uid.split('@').split(':')[1] + + $obj = [PSCustomObject]@{ + 'Name' = $VM.Name; + 'AppName' = $AppName; + 'CohesityGB' = $CohesityGB + 'OldTag' = $OldTag; + 'vCenter' = $vCenter; + } + + #Write-Output $obj + $null = $result.Add($obj) +} + +$group = $result | group-object AppName | select Count,Name,@{n='CohesityGB';e={($_.Group | measure-object -sum CohesityGB).sum}}#,@{n='NotCohesityGB';e={}} + +#Get-Tag -Category AppName -Name DHS-SPACES \ No newline at end of file diff --git a/Cohesity-AppNamesWithSQL.ps1 b/Cohesity-AppNamesWithSQL.ps1 new file mode 100644 index 0000000..5eb6dd9 --- /dev/null +++ b/Cohesity-AppNamesWithSQL.ps1 @@ -0,0 +1,47 @@ +$AppNamesWithSQL=@" +BND-APCheck +BND-Fiserv +BND-FUNDTECH +BND-Reporting +BND-SQL +CJIS-Justware-SQL +CJIS-LERMS-SQL +DEQ-nVIRO +DES-CAD +DHS-Avatar-SQL +DHS-MMIS-MoveIT +DHS-MMIS-Truven-Windows +DHS-MMIS-Xpressions-SQL +DHS-Pyxis +DHS-VISION +DOH-WIC +DOT-GIS +DOT-HEAT-SQL +DOT-RoadTest +DOT-STARS +HPN-Video +Infra-Desktop-SCCM-SQL +Infra-Passwordstate +Infra-Security-Investigation +Infra-Security-MFA-SafeNet +Infra-Security-MFA-SafeNet-SQL +Infra-Servers-SCCM-SQL +ITD-EDUTec-K12FIM-SQL +ITD-POC-Desktop +ITD-SLDS +ITD-SLDS-EDFI-ODS +JSN-EAE +RRI-Macola +Shared-PeopleSoft-HigherEd +Shared-PeopleSoft-State +Shared-SharePoint-SQL +Shared-SQL +Shared-SQL-DR +SOS-BPRO-SQL +SOS-CentralIndexing +TAX-GenTax +WSI-Extranet-SQL +WSI-Reporting +"@ + +$AppNamesWithSQL = ConvertTo-Array -MultiLineString $AppNamesWithSQL \ No newline at end of file diff --git a/Cohesity-EnableDisableProtectionGroupBasedOnCount.ps1 b/Cohesity-EnableDisableProtectionGroupBasedOnCount.ps1 new file mode 100644 index 0000000..a33e855 --- /dev/null +++ b/Cohesity-EnableDisableProtectionGroupBasedOnCount.ps1 @@ -0,0 +1,82 @@ +$AllCohesityProtectionGroups = Get-CohesityProtectionJob | Where-Object Environment -eq kVMware | sort-object Name +$AllCohesityVMwareVM = Get-CohesityVMwareVM + +$toDisable=@() + +ForEach($ProtectionJob in $AllCohesityProtectionGroups){ + $IncludeTags = $ProtectionJob.vmTagIds[0][0] + If($ProtectionJob.excludeVmTagIds[0][0]){ + $ExcludeTags = $ProtectionJob.excludeVmTagIds[0][0] + } + + + $IncludeVMs = $AllCohesityVMwareVM | where-object {$_.VmWareProtectionSource.TagAttributes.Id -eq $IncludeTags} | Sort-object Name + If($ProtectionJob.excludeVmTagIds[0][0]){ + $ExcludeVMs = $AllCohesityVMwareVM | where-object {$_.VmWareProtectionSource.TagAttributes.Id -eq $IncludeTags -and $_.VmWareProtectionSource.TagAttributes.Id -eq $ExcludeTags} | Sort-object Name + } + Else{ + $ExcludeVMs = $null + } + + $VMsToBackup = $IncludeVMs | where-object {$ExcludeVMs -notcontains $_} + + If(@($VMsToBackup).count -ge 1){ + # enable protection job + #$ProtectionJob.isPaused = $False + #$ProtectionJob | Set-CohesityProtectionJob -Confirm:$false + } + Else{ + # disable protection job + #$ProtectionJob.isPaused = $True + #$ProtectionJob | Set-CohesityProtectionJob -Confirm:$false + $toDisable += $ProtectionJob + } +} + + + +<# +"tagAttributes": [ + { + "gcpTagType": null, + "id": 8334, + "name": "Reserved", + "uuid": "urn:vmomi:InventoryServiceTag:7ec35aab-9234-4324-93c3-695e5664ed74:GLOBAL" + }, + { + "gcpTagType": null, + "id": 3407, + "name": "Shared-PowerSchool", + "uuid": "urn:vmomi:InventoryServiceTag:996627f1-ee30-4d92-8249-b1aa71c63d75:GLOBAL" + }, + { + "gcpTagType": null, + "id": 7065, + "name": "Windows Server 2012 R2 Standard (64-Bit)", + "uuid": "urn:vmomi:InventoryServiceTag:89e77b90-2876-476d-a346-2c9da6583ce9:GLOBAL" + }, + { + "gcpTagType": null, + "id": 3223, + "name": "ABR", + "uuid": "urn:vmomi:InventoryServiceTag:31bda67f-a610-460c-bd7c-75cc1adeb4c6:GLOBAL" + }, + { + "gcpTagType": null, + "id": 3205, + "name": "4", + "uuid": "urn:vmomi:InventoryServiceTag:3fd9b786-5d50-42b1-912e-95b9f0262891:GLOBAL" + }, + { + "gcpTagType": null, + "id": 3225, + "name": "Production", + "uuid": "urn:vmomi:InventoryServiceTag:3d04149e-c1aa-4f46-a7f5-f0cfcb1b4414:GLOBAL" + }, + { + "gcpTagType": null, + "id": 7108, + "name": "No Licensing Restrictions", + "uuid": "urn:vmomi:InventoryServiceTag:049ee6ff-5205-4b2c-bc20-a0c44e2eb05c:GLOBAL" + } +#> \ No newline at end of file diff --git a/Cohesity-NewBuildTracking.ps1 b/Cohesity-NewBuildTracking.ps1 new file mode 100644 index 0000000..38c5286 --- /dev/null +++ b/Cohesity-NewBuildTracking.ps1 @@ -0,0 +1,119 @@ +$Filter = '&$select=ID,Title,DateCreated,Status,DataCenter,Environment,StartupPriority,OS,Processors,RAM,DiskTotal,DataProtection,DR_Protection,SRM_RecoveryVMtype,LicensingRestrictions,Network/Vlan_Id,Network/CIDR,AppName/Title,Cluster/Name&$expand=Network/Id,AppName/Id,Cluster/Id' +$URLVMItems = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VM Guests')/items?" + '$top=10000' + $Filter +$InvokeRestMethodParams = @{ + Uri = $URLVMItems; + Method = "Get"; + headers = @{ "Accept" = "application/json;odata=verbose" }; + UseBasicParsing = $true; +} +$z = (Invoke-RestMethod @InvokeRestMethodParams -UseDefaultCredentials) -creplace '"Id":', '"Idx":' | ConvertFrom-Json +$VMList = $z.d.results + +$URLAppNames = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VM App Name')/items?" + '$top=10000' +$InvokeRestMethodParams = @{ + Uri = $URLAppNames; + Method = "Get"; + headers = @{ "Accept" = "application/json;odata=verbose" }; + UseBasicParsing = $true; +} +$z = (Invoke-RestMethod @InvokeRestMethodParams -UseDefaultCredentials) -creplace '"Id":', '"Idx":' | ConvertFrom-Json +$AppNameList = $z.d.results + +$AllAppNameVMs = $AppNameList | where-object Cohesity -eq "All VMs" +$NewAppNameVMs = $AppNameList | where-object Cohesity -eq "New VMs Only" + + +# compare new vm list to cohesity vm list +$NewVMs = $VMList | where-object DateCreated -gt (Get-Date -Year 2021 -Month 2 -Day 1) + +$CohesityVMs = Get-CohesityVMwareVM -Protected + +$compare = Compare-Object -ReferenceObject $NewVMs.Title -DifferenceObject $CohesityVMs.Name +$VMsToAdd = $compare | where-object Sideindicator -eq "<=" +$VMsToAddAppNames = $VMsToAdd.InputObject | forEach-object { ($VMList | where-object Title -eq $_).AppName.Title } | Select-Object -unique + +$AllProtectionGroups = Get-CohesityProtectionJob + +$AllProtectionSourceObject = Get-CohesityProtectionSourceObject +$AppNamesToReview = [System.Collections.ArrayList]@() +ForEach ($AppName in $VMsToAddAppNames) { + $SourceObjects = $AllProtectionSourceObject | Where-Object Name -eq $AppName + $ExistingPGs = Get-CohesityProtectionJob -Names $AppName + + If ($ExistingPGs) { + $PGsWithTags = $ExistingPGs | where-object { $_.vmTagIds -match '8744' -or $_.vmTagIds -match '8747' } + If ($PGsWithTags) { $Style = "Tagged VMs" } + Else { $Style = "All VMs" } + + $obj = [PSCustomObject]@{ + AppName = $AppName; + Style = $Style + } + } + Else { + $obj = [PSCustomObject]@{ + AppName = $AppName; + Style = "New PG, needs human" + } + } + $null = $AppNamesToReview.Add($obj) +} + +$AppNamesToReview | sort-object AppName + +ForEach ($item in $VMsToAdd) { + $SPItem = $null + + # get appname, then appname metadata + $VMSPItem = $VMList | where-object Title -eq $item.InputObject + $AppName = $VMSPItem.AppName.Title + $AppNameSPItem = $AppNameList | where-object Title -eq $AppName + + + ForEach ($SourceObject in $SourceObjects) { + switch ($AppNameSPItem.Cohesity) { + $null { + If ($AppNameSPItem.Created -gt (Get-Date -Year 2021 -Month 2 -Day 1)) { + # created after 2021-02-01, set "All VMs" + $AppNameProtection = "All VMs" + } + Else { + # created before 2021-02-01, set "New VMs" + $AppNameProtection = "New VMs Only" + + } + + } + } + } + + # find if protection group exists + $CohesityPGs = Get-CohesityProtectionJob -Names $AppName + If ($CohesityPGs) { + + } + Else { + New-ITDCohesityProtectionGroupWIP -AppName $AppName + switch ($AppNameProtection) { + 'All VMs' { + # do nothing + } + 'New VMs Only' { + + } + } + } + # create protection group if needed, configure for "All VMs" condition, end + # if protection group exists, find out if protect all VMs, or just new + # if all VMs, no work to do + # if new VMs, add VM to protection group + + + +} + +# Cohesity Protection Groups with the entire AppName protected +Get-CohesityProtectionJob | Where-Object { $_.vmTagIds -notmatch 8747 -and $_.vmTagIds -notmatch 8744 } | sort-object Name + +# Cohesity Protection Groups with only new AppName VMs protected +Get-CohesityProtectionJob | Where-Object { $_.vmTagIds -match 8747 -or $_.vmTagIds -match 8744 } | sort-object Name diff --git a/Cohesity-ProtectionGroupsIndexing.ps1 b/Cohesity-ProtectionGroupsIndexing.ps1 new file mode 100644 index 0000000..6be9a81 --- /dev/null +++ b/Cohesity-ProtectionGroupsIndexing.ps1 @@ -0,0 +1,29 @@ +# list +$ProtectionGroups = Get-CohesityProtectionJob | where-object environment -eq kVMware | sort-object Name +$ProtectionGroups | Select-Object name, @{n = 'AllowPrefixes'; e = { $_.indexingpolicy.allowprefixes } }, @{n = 'DenyPrefixes'; e = { $_.indexingpolicy.denyprefixes } } | sort-object Name + +<#ignore +program files x2 +var +#> +$indexingPolicy = [PSCustomObject]@{ + disableIndexing = $false; + allowPrefixes = @('/'); + denyPrefixes = @('/$Recycle.Bin','/Windows','/ProgramData','/System Volume Information','/Users/*/AppData','/Recovery','/usr','/sys','/proc','/lib','/grub','/grub2','opt/splunk','/splunk') +} + + +#$ProtectionJob = Get-CohesityProtectionJob -Names "DOH-StarLIMS@itdvmvc1" +$ProtectionGroups = Get-CohesityProtectionJob | where-object environment -eq kVMware | sort-object Name +ForEach ($ProtectionJob in $ProtectionGroups) { + If($ProtectionJob.indexingPolicy){ + $ProtectionJob.indexingPolicy = $indexingPolicy + } + Else + { + $ProtectionJob | Add-Member -MemberType NoteProperty -Name indexingPolicy -Value $indexingPolicy + } + + Set-CohesityProtectionJob -ProtectionJob $ProtectionJob -Confirm:$false +} + diff --git a/Cohesity-RemoteServiceChanges.ps1 b/Cohesity-RemoteServiceChanges.ps1 new file mode 100644 index 0000000..b5afb49 --- /dev/null +++ b/Cohesity-RemoteServiceChanges.ps1 @@ -0,0 +1,25 @@ +$func = { + #Add to Local Security Policy + function Add-ServiceLogonRight([string] $Username) { + Write-Host "Enable ServiceLogonRight for $Username" + + $tmp = New-TemporaryFile + secedit /export /cfg "$tmp.inf" | Out-Null + (Get-Content -Encoding ascii "$tmp.inf") -replace '^SeServiceLogonRight .+', "`$0,$Username" | sc -Encoding ascii "$tmp.inf" + secedit /import /cfg "$tmp.inf" /db "$tmp.sdb" | Out-Null + secedit /configure /db "$tmp.sdb" /cfg "$tmp.inf" | Out-Null + Remove-Item $tmp* -ea 0 +} + +Add-ServiceLogonRight -Username svccohesityadm + +# Set Service to Run as Service Account +Stop-Service -Name CohesityAgent +sc.exe config "CohesityAgent" obj="NDGOV\svccohesityadm" password="memo-fUpHMMgXnv" +Start-Service -Name CohesityAgent + +# Add to Local Administrators group +Add-LocalGroupMember -Group Administrators -Member "ndgov\svccohesityadm" +} + +Invoke-Command -ComputerName itddhssql19p1.nd.gov -Credential $PrvCred -ScriptBlock $func \ No newline at end of file diff --git a/Cohesity-ServiceRunAs.ps1 b/Cohesity-ServiceRunAs.ps1 new file mode 100644 index 0000000..2116129 --- /dev/null +++ b/Cohesity-ServiceRunAs.ps1 @@ -0,0 +1,21 @@ +#Add to Local Security Policy +function Add-ServiceLogonRight([string] $Username) { + Write-Host "Enable ServiceLogonRight for $Username" + + $tmp = New-TemporaryFile + secedit /export /cfg "$tmp.inf" | Out-Null + (Get-Content -Encoding ascii "$tmp.inf") -replace '^SeServiceLogonRight .+', "`$0,$Username" | sc -Encoding ascii "$tmp.inf" + secedit /import /cfg "$tmp.inf" /db "$tmp.sdb" | Out-Null + secedit /configure /db "$tmp.sdb" /cfg "$tmp.inf" | Out-Null + Remove-Item $tmp* -ea 0 +} + +Add-ServiceLogonRight -Username svccohesitysql + +# Set Service to Run as Service Account +Stop-Service -Name CohesityAgent +sc.exe config "CohesityAgent" obj="NDGOV\svccohesitysql" password="radiant-yx8aHMrGtc" +Start-Service -Name CohesityAgent + +# Add to Local Administrators group +Add-LocalGroupMember -Group Administrators -Member "ndgov\svccohesitysql" \ No newline at end of file diff --git a/CohesityTests.ps1 b/CohesityTests.ps1 new file mode 100644 index 0000000..60b93c8 --- /dev/null +++ b/CohesityTests.ps1 @@ -0,0 +1,28 @@ + +$ProtectionJob = Get-CohesityProtectionJob -Names "ZM-Performance Test Bismarck" +$VMwareVM = Get-CohesityVMwareVM -Protected -Names itdvmutil.nd.gov +$ProtectionSourceObject = Get-CohesityProtectionSourceObject -Environments KVMware | Where-Object Name -eq "itdvmutil.nd.gov" + +# 4312 +# 3156 +# 4584 +# 3156 + +Restore-CohesityFile -TaskName "zmRestoreFileTest" ` + -FileNames /D/Upgrades/VMware/old/VMware-VCSA-all-6.5.0U3g-14836121.iso ` + -JobId $ProtectionJob.Id ` + -SourceId ($ProtectionSourceObject | Select -Unique ParentId).ParentId ` + -TargetSourceId $VMwareVM.Id ` + -TargetParentSourceId $VMwareVM.ParentId ` + -TargetHostType KWindows ` + -TargetHostCredential (Get-Credential) + + +Restore-CohesityFile -TaskName "restore-file-vm" ` + -FileNames /C/data/file.txt ` + -JobId 1234 ` + -SourceId 843 ` + -TargetSourceId 856 ` + -TargetParentSourceId 828 ` + -TargetHostType KWindows ` + -TargetHostCredential (Get-Credential) diff --git a/Copy-ITDRemoteFiles.ps1 b/Copy-ITDRemoteFiles.ps1 new file mode 100644 index 0000000..8e8024b --- /dev/null +++ b/Copy-ITDRemoteFiles.ps1 @@ -0,0 +1,6 @@ +$AdminCred = Get-Credential # run once console session + +$PSSession = New-PSSsession -ComputerName itddeqappt1.nd.gov -Credential $AdminCred + +Copy-Item -Path C:\localpath.txt -ToSession $PSSession -Destination C:\ +Copy-Item -Path C:\remotepath.txt -FromSession $PSSession -Destination C:\ \ No newline at end of file diff --git a/ESU-licensing-v3.1.ps1 b/ESU-licensing-v3.1.ps1 new file mode 100644 index 0000000..2909784 --- /dev/null +++ b/ESU-licensing-v3.1.ps1 @@ -0,0 +1,82 @@ +#MAK & ESU remediation v3.1 + +$OS = (Get-WMIObject Win32_OperatingSystem).Caption +write-verbose $OS + +switch ($OS) { + 'Microsoft Windows Server 2008 R2 Datacenter ' { + write-verbose "switch datacenter edition" + $MakId = '4ae528f4-05c3-446e-90ea-a4fbd460b83a' + $MakKey = '33YCD-89CD2-RMYVW-RGX7W-R9XRM' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' #activationid + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + $Esu3Id = '16c08c85-0c8b-4009-9b2b-f1f7319e45f9' + $Esu3Key = '36FB4-RK77J-C867T-QPJBT-4PMW6' + } + 'Microsoft Windows Server 2008 R2 Enterprise ' { + write-verbose "switch enterprise edition" + $MakId = '6a4bd364-4b60-4856-a727-efb59d94348e' + $MakKey = 'TB9WQ-WKHVH-W7946-WJTVV-Y6QDD' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + $Esu3Id = '16c08c85-0c8b-4009-9b2b-f1f7319e45f9' + $Esu3Key = '36FB4-RK77J-C867T-QPJBT-4PMW6' + } + 'Microsoft Windows Server 2008 R2 Standard ' { + write-verbose "switch standard edition" + $MakId = '' + $MakKey = 'TB9WQ-WKHVH-W7946-WJTVV-Y6QDD' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + $Esu3Id = '16c08c85-0c8b-4009-9b2b-f1f7319e45f9' + $Esu3Key = '36FB4-RK77J-C867T-QPJBT-4PMW6' + } + 'Microsoft Windows 7 Enterprise ' { + write-verbose "switch Win7 enterprise edition" + $MakId = '9abf5984-9c16-46f2-ad1e-7fe15931a8dd' + $MakKey = 'PRV3H-98HJK-6KKBF-RHYTM-JWCRV' + $Esu1Id = '77db037b-95c3-48d7-a3ab-a9c6d41093e0' + $Esu1Key = 'MJCJ8-24DFX-VGK6H-XYBQ7-F6PR8' + $Esu2Id = '0e00c25d-8795-4fb7-9572-3803d91b6880' + $Esu2Key = 'WX34W-WG8MH-TWWCV-PXK96-RDMTJ' + $Esu3Id = '4220f546-f522-46df-8202-4d07afd26454' + $Esu3Key = 'TF336-89RVD-X2FJJ-YV3KF-Q6KPF' + } + 'Microsoft® Windows Server® 2008 Standard ' { + write-verbose "switch 08 Standard" + $MakId = 'ad2542d4-9154-4c6d-8a44-30f11ee96989' + $MakKey = 'GQK9D-CT4WQ-9KJ87-FKMT8-MR73Q' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + $Esu3Id = '16c08c85-0c8b-4009-9b2b-f1f7319e45f9' + $Esu3Key = '36FB4-RK77J-C867T-QPJBT-4PMW6' + } + 'Microsoft® Windows Server® 2008 Enterprise ' { + write-verbose "switch 08 Enterprise" + $MakId = 'bb1d27c4-959d-4f82-b0fd-c02a7be54732' + $MakKey = 'GQK9D-CT4WQ-9KJ87-FKMT8-MR73Q' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + $Esu3Id = '16c08c85-0c8b-4009-9b2b-f1f7319e45f9' + $Esu3Key = '36FB4-RK77J-C867T-QPJBT-4PMW6' + } +} + +#cscript C:\Windows\System32\slmgr.vbs -ipk $MakKey +#cscript C:\Windows\System32\slmgr.vbs -ato $MakId +cscript C:\Windows\System32\slmgr.vbs -ipk $Esu1Key +cscript C:\Windows\System32\slmgr.vbs -ato $Esu1Id +cscript C:\Windows\System32\slmgr.vbs -ipk $Esu2Key +cscript C:\Windows\System32\slmgr.vbs -ato $Esu2Id +cscript C:\Windows\System32\slmgr.vbs -ipk $Esu3Key +cscript C:\Windows\System32\slmgr.vbs -ato $Esu3Id \ No newline at end of file diff --git a/ESU-licensing.ps1 b/ESU-licensing.ps1 new file mode 100644 index 0000000..cb9dac3 --- /dev/null +++ b/ESU-licensing.ps1 @@ -0,0 +1,126 @@ +$servers = @" +itdcjissqlt1.nd.gov +itddlmacpt1.nd.gov +itddlmdev1.nd.gov +itddlmsit1.nd.gov +itddlmtrng1.nd.gov +itddlmuat1.nd.gov +itdnett1.nd.gov +itdombnett1.nd.gov +"@ + +$servers = ConvertTo-Array -MultiLineString $servers + +Invoke-Command -ComputerName $servers -Credential $AdminCred -scriptblock {Get-Process ccmexec,ccmsetup -ErrorAction SilentlyContinue} + +# validation +$ESUbool = $false +$KMSbool = $false + +$OS = (Get-WMIObject Win32_OperatingSystem).Caption +write-verbose $OS +switch ($OS) { + 'Microsoft Windows Server 2008 R2 Datacenter ' { + write-verbose "switch datacenter edition" + $KMSId = '7482e61b-c589-4b7f-8ecc-46d455ac3b87' + $KMSClientKey = '74YFP-3QFB3-KQT8W-PMXWJ-7M648' + $ESUId = '553673ed-6ddf-419c-a153-b760283472fd' + } + 'Microsoft Windows Server 2008 R2 Enterprise ' { + write-verbose "switch enterprise edition" + $KMSId = '620e2b3d-09e7-42fd-802a-17a13652fe7a' + $KMSClientKey = '489J6-VHDMP-X63PK-3K798-CPX3Y' + $ESUId = '553673ed-6ddf-419c-a153-b760283472fd' + } + 'Microsoft Windows Server 2008 R2 Standard ' { + write-verbose "switch standard edition" + $KMSId = '' + $KMSClientKey = 'YC6KT-GKW9T-YTKYR-T4X34-R7VHC' + $ESUId = '553673ed-6ddf-419c-a153-b760283472fd' + } + 'Microsoft Windows 7 Enterprise '{ + write-verbose "switch Win7 enterprise edition" + $KMSId = 'ae2ee509-1b34-41c0-acb7-6d4650168915' + $KMSClientKey = 'YC6KT-GKW9T-YTKYR-T4X34-R7VHC' + $ESUId = '77db037b-95c3-48d7-a3ab-a9c6d41093e0' + } + 'Microsoft® Windows Server® 2008 Standard '{ + write-verbose "switch Win7 enterprise edition" + $KMSId = 'ad2542d4-9154-4c6d-8a44-30f11ee96989' + $KMSClientKey = 'TM24T-X9RMF-VWXK6-X8JC9-BFGM2' + $ESUId = '553673ed-6ddf-419c-a153-b760283472fd' + } +} + +$software = Get-WMIObject -Class SoftwareLicensingProduct + +$ESUYear1 = $software | Where-Object { $_.Id -eq $ESUId } +If ($ESUYear1) { + If ($ESUYear1.LicenseStatus -eq '1') { + $ESUbool = $true + } +} + +$KMS = $software | where-object { $_.Id -eq $KMSId } +If ($KMS) { + If ($KMS.LicenseStatus -eq 1) { + $KMSbool = $true + } +} + +If ($ESUbool -eq $true -and $KMSbool -eq $true) { + $compliant = $true +} +else { + $compliant = $false +} + +$compliant + + +#remediation +$OS = (Get-WMIObject Win32_OperatingSystem).Caption +switch ($OS) { + 'Microsoft Windows Server 2008 R2 Datacenter ' { + write-verbose "switch datacenter edition" + $KMSId = '7482e61b-c589-4b7f-8ecc-46d455ac3b87' + $KMSClientKey = '74YFP-3QFB3-KQT8W-PMXWJ-7M648' + $ESUKey = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $ESUId = '553673ed-6ddf-419c-a153-b760283472fd' + } + 'Microsoft Windows Server 2008 R2 Enterprise ' { + write-verbose "switch enterprise edition" + $KMSId = '' + $KMSClientKey = '489J6-VHDMP-X63PK-3K798-CPX3Y' + $ESUKey = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $ESUId = '553673ed-6ddf-419c-a153-b760283472fd' + } + 'Microsoft Windows Server 2008 R2 Standard ' { + write-verbose "switch standard edition" + $KMSId = '' + $KMSClientKey = 'YC6KT-GKW9T-YTKYR-T4X34-R7VHC' + $ESUKey = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $ESUId = '553673ed-6ddf-419c-a153-b760283472fd' + } + 'Microsoft Windows 7 Enterprise ' { + write-verbose "switch Win7 Enterprise" + $KMSId = 'ae2ee509-1b34-41c0-acb7-6d4650168915' + $KMSClientKey = '33PXH-7Y6KF-2VJC9-XBBR8-HVTHH' + $ESUKey = 'MJCJ8-24DFX-VGK6H-XYBQ7-F6PR8' + $ESUId = '77db037b-95c3-48d7-a3ab-a9c6d41093e0' + } + 'Microsoft® Windows Server® 2008 Standard '{ + write-verbose "switch Win7 enterprise edition" + $KMSId = 'ad2542d4-9154-4c6d-8a44-30f11ee96989' + $KMSClientKey = 'TM24T-X9RMF-VWXK6-X8JC9-BFGM2' + $ESUKey = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $ESUId = '553673ed-6ddf-419c-a153-b760283472fd' + } +} + +cscript C:\Windows\System32\slmgr.vbs -ipk $KMSClientKey +cscript C:\Windows\System32\slmgr.vbs -skms itdkms2.nd.gov +cscript C:\Windows\System32\slmgr.vbs -ato $KMSId +cscript C:\Windows\System32\slmgr.vbs -ipk $ESUKey +cscript C:\Windows\System32\slmgr.vbs -ato $ESUId +cscript C:\windows\system32\slmgr.vbs /dlv diff --git a/ESU-servers.ps1 b/ESU-servers.ps1 new file mode 100644 index 0000000..edf3b60 --- /dev/null +++ b/ESU-servers.ps1 @@ -0,0 +1,85 @@ +$servers=@" +bnd0424.bnd.nd.gov +bnd0425.bnd.nd.gov +bnd0426.bnd.nd.gov +bnd0427.bnd.nd.gov +bnd0430.bnd.nd.gov +bnd0431.bnd.nd.gov +bnd0432.bnd.nd.gov +bnd0433.bnd.nd.gov +bnd0434.bnd.nd.gov +bnd0436.bnd.nd.gov +bnd0437.bnd.nd.gov +bnd0555.nd.gov +bnd0559.nd.gov +bnd0560.nd.gov +bnd0655.nd.gov +bnd0656.nd.gov +bndapp12.bnd.nd.gov +descadlive.nd.gov +descadtrain.nd.gov +dhssosrvlnapp.itd.nd.gov +dhssosrvlnhub.itd.nd.gov +itdapp7.itd.nd.gov +itdapp8.nd.gov +itdcjissqlp1.nd.gov +itdcjissqlrep1.nd.gov +itdcjissqlt1.nd.gov +itdcogmmisprm.prm.mmis.nd.gov +itdcogmmisprm2.prm.mmis.nd.gov +itdcogmmissit.sit.mmis.nd.gov +itdcogmmistrn.trn.mmis.nd.gov +itdcogmmisuat.uat.mmis.nd.gov +itddhsmmisjhd.nd.gov +itddlmacpt1.nd.gov +itddlmdev1.nd.gov +itddlmprtprod.nd.gov +itddlmsit1.nd.gov +itddlmtrng1.nd.gov +itddlmuat1.nd.gov +itddocemrrdp1.nd.gov +itddohvid.itd.nd.gov +itddotgisweb.nd.gov +itdgeolynx2.itd.nd.gov +itdgnfcody2.nd.gov +itdmciwkbench.itd.nd.gov +itdmfa1.nd.gov +itdmfa2.nd.gov +itdmfa3.nd.gov +itdmfasql1.nd.gov +itdmfasql2.nd.gov +itdmmistmart.nd.gov +itdnaom1.itd.nd.gov +itdnet35p1.itd.nd.gov +itdnet35p2.itd.nd.gov +itdnet35t1.itd.nd.gov +itdnet35t2.itd.nd.gov +itdnetp1.itd.nd.gov +itdnett1.itd.nd.gov +itdombnetp1.nd.gov +itdombnett1.nd.gov +itdopenscan1.itd.nd.gov +itdopenscan1tst.itd.nd.gov +itdopenscan2.itd.nd.gov +itdprmxpr4.mmis.nd.gov +itdprmxprsql1.mmis.nd.gov +itdratrpt1.mmis.nd.gov +itdratrpt2.mmis.nd.gov +itdratrpt3.mmis.nd.gov +itdratrpt4.mmis.nd.gov +itdratrpt5.mmis.nd.gov +itdsitxpr4.mmis.nd.gov +itduatxpr4.mmis.nd.gov +itdwsiitsm.nd.gov +nodak00.itd.nd.gov +nodak02.itd.nd.gov +nodak04.itd.nd.gov +wsiapp1.itd.nd.gov +ITDDOTFRSQL1.nd.gov +ITDDOTFRWeb1.nd.gov +ITDDOTFRAPP1.nd.gov +"@ + +$servers = ConvertTo-Array -MultiLineString $servers + +$result = $servers | ForEach-Object -Parallel {resolve-dnsname $_ | select Name,IPAddress} \ No newline at end of file diff --git a/Get-VMVRDatastores.ps1 b/Get-VMVRDatastores.ps1 new file mode 100644 index 0000000..e1464be --- /dev/null +++ b/Get-VMVRDatastores.ps1 @@ -0,0 +1,21 @@ +$Datastores = Get-Datastore *224*, *225*, *226* +$Folders = @() +ForEach ($Datastore in $Datastores) { + $DatastoreName = $Datastore.Name + $Folders += Get-ChildItem "vmstores:\itdvmvc2.nd.gov@443\Secondary Datacenter\$DatastoreName" | where-object { $_.ItemType -eq "Folder" -and $_.Name -ne '.dvsData' -and $_.Name -ne '.sdd.sf' -and $_.Name -ne '.vSphere-HA' } +} + +$result = @() +ForEach ($Folder in $Folders) { + $obj = [PSCustomObject]@{ + Datastore = $Folder.PSPath.split('\')[-2]; + Folder = $Folder.Name; + SizeGB = [math]::Round(((Get-ChildItem -Path $Folder.FullName) | Measure-Object -Property Length -Sum).Sum / 1GB, 2); + } + $result += $obj +} + +$VMs = Get-VM $Folders.Name | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" } -ErrorAction SilentlyContinue | sort-object Name +Compare-Object $Folders.Name $VMs.Name | sort-object InputObject + +F \ No newline at end of file diff --git a/Get-Weather.ps1 b/Get-Weather.ps1 new file mode 100644 index 0000000..6e1f4d7 --- /dev/null +++ b/Get-Weather.ps1 @@ -0,0 +1,12 @@ +$x=(Invoke-WebRequest -Uri 'https://api.darksky.net/forecast/974eb758cd9ed981450e20a6ebd9427d/46.849925,-100.781303').content | convertfrom-json + + +"1575065880" +[DateTimeOffset]::FromUnixTimeSeconds(1575064339) + + +(Invoke-RestMethod -uri 'https://api.darksky.net/forecast/974eb758cd9ed981450e20a6ebd9427d/46.849925,-100.781303').Content | clip + + + +((Invoke-WebRequest -Uri 'https://api.darksky.net/forecast/974eb758cd9ed981450e20a6ebd9427d/46.849925,-100.781303').content | convertfrom-json).currently \ No newline at end of file diff --git a/HPEILO-Certificates.ps1 b/HPEILO-Certificates.ps1 new file mode 100644 index 0000000..7063392 --- /dev/null +++ b/HPEILO-Certificates.ps1 @@ -0,0 +1,74 @@ +# confirmed working on DL380 Gen10 with HPEiLOCmdlets version 3.2.0.0 +# 2024/02/05 -- still requires PowerShell 5.1 "for some reason" +### #####itdvmmdnwin11lo.nd.gov + +#$iLOCred = Get-Secret -Name IloSboxCred +Import-Module HPEiLOCmdlets + +$iLOCred = Get-Credential +$iLOFQDNs = @" +itdvmbisps16lo.nd.gov +itdvmbiswas09lo.nd.gov +"@ + +<# + + +#> +$iLOFQDNs = ConvertTo-Array -MultiLineString $iLOFQDNs + +$iLOConnections = ForEach ($iLOFQDN in $iLOFQDNs) { + Connect-HPEiLO -Address $iLOFQDN -Credential $iLOCred -DisableCertificateAuthentication +} + +Get-HPEiLOSSLCertificateInfo -Connection $iLOConnections -ov x + +ForEach ($iLOConnection in $iLOConnections) { + Start-HPEiLOCertificateSigningRequest -Connection $iLOConnection ` + -CommonName $iloConnection.Hostname ` + -Organization "State of North Dakota" ` + -Country US ` + -City Bismarck ` + -State "North Dakota" ` + -OrganizationalUnit NDIT +} +Start-Sleep -Seconds 30 + +#wait 30 seconds, then continue -- will copy CSR to clipboard, paste it into Ansible playbook, vmware@nd.gov for email, hit Enter and loop + +ForEach ($iLOConnection in $iLOConnections) { + $CSR = Get-HPEiLOCertificateSigningRequest -Connection $iLOConnection + Write-Warning -Message ("Start " + $CSR.Hostname) + $CSR.CertificateSigningRequest | Set-Clipboard + Pause +} + +#### send csr to ca + +# get certificate back, updating download folder below as needed +# download the "Certificate only, PEM encoded" cert + +ForEach ($iLOFQDN in $iLOFQDNs) { + Write-Warning -Message "Start $iloFQDN" + $cert = Get-ChildItem D:\Downloads | Where-Object { $_.Name -eq ($iLOFQDN.replace(".", "_") + "_cert.cer") } | Get-Content + $connection = $iLOConnections | Where-Object Hostname -EQ $iLOFQDN + Import-HPEiLOCertificate -Certificate ($cert | Out-String) -Connection $connection + Write-Warning -Message "End $iloFQDN" +} + +# OneView, refresh server hardware + + +# validate certificate after 30 seconds / iLO reset +[Net.ServicePointManager]::ServerCertificateValidationCallback = { $true } +ForEach ($iloFQDN in $iLOFQDNs) { + $url = ("https://" + $iloFQDN) + $req = [Net.HttpWebRequest]::Create($Url) + $req.GetResponse() | Out-Null + $output = [PSCustomObject]@{ + URL = $url + 'Cert Start Date' = $req.ServicePoint.Certificate.GetEffectiveDateString() + 'Cert End Date' = $req.ServicePoint.Certificate.GetExpirationDateString() + } + $output +} diff --git a/HelloWorld.ps1 b/HelloWorld.ps1 new file mode 100644 index 0000000..96644e2 --- /dev/null +++ b/HelloWorld.ps1 @@ -0,0 +1,3 @@ +New-Item C:\HelloWorld.txt -Force +Set-Content -Path C:\HelloWorld\HelloWorld.txt -Value (Get-Date) +### 1 \ No newline at end of file diff --git a/HomeDrive - Copy.ps1 b/HomeDrive - Copy.ps1 new file mode 100644 index 0000000..a07b974 --- /dev/null +++ b/HomeDrive - Copy.ps1 @@ -0,0 +1,57 @@ +$Filter = "(samaccountname=$env:username)" +$RootOU = "dc=nd,dc=gov" + +Write-Warning $Filter + +$Searcher = New-Object DirectoryServices.DirectorySearcher +$Searcher.Filter = $Filter +$result=$Searcher.FindAll() + +$homedir = $result.properties.homedirectory +$homedrive = $result.properties.homedrive +$ScriptPath = $result.properties.scriptpath + +If($ScriptPath) +{ + $LoginScript = "\\nd.gov\netlogon\$ScriptPath" + Start-Process "cmd.exe" "/c $loginscript" #<< run loginscript +} + +If($homedrive) +{ + New-PSDrive -Name $homedrive.TrimEnd(':') -PSProvider FileSystem -Root $homedir -Persist +} + + +# SIG # Begin signature block +# MIIFdgYJKoZIhvcNAQcCoIIFZzCCBWMCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB +# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR +# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUEapmZ+ZgSAHkkFVI1S3u06dz +# OdmgggMOMIIDCjCCAfKgAwIBAgIQVQoeTLrf5bJKxVZKPVHSEzANBgkqhkiG9w0B +# AQUFADAdMRswGQYDVQQDDBJMb2NhbCBDb2RlIFNpZ25pbmcwHhcNMjAwMzI0MTky +# NzA3WhcNMjEwMzI0MTk0NzA3WjAdMRswGQYDVQQDDBJMb2NhbCBDb2RlIFNpZ25p +# bmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDARE6vqPLMQ8HioO0e +# O4ryGzcLqfRh3CERGbhSaG4sWxQMWPZWjuYPiYx4CT6rRezzN5ZZSvDVeKBuXTID +# uS9419zgoY8e+L9PBRLyvjFIHTEFvNcbUeX3KyrOUuxOgcMx2ByrbcLSWd2R0ZKW +# L0unmS79073fz49eH+6ixE8VLf55A7bOJ/q/nfPDr8OEhqaCX/aToAIQHd2AMw9M +# G3wZQLWbxs1Re2icogumo2i1DFoPoTbaSeW7ew4762QonUfETLz793EPGFOnopW+ +# i8T5o6KjsP4SFOlooi0KOParXAE/S6NSRHpdIHs4KqSw8J3Y1/x8A0AihasnbBbG +# EaZ9AgMBAAGjRjBEMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcD +# AzAdBgNVHQ4EFgQULC0jVuwflxdsAkkw3yKVtsNo01cwDQYJKoZIhvcNAQEFBQAD +# ggEBAG+2XCn7n5Q0sV56xynZ64bLdNy/j/ahMND2Hgk/kXbeDYb56M49CLrJluls +# 5i7tChwDxCp6+y+tQxiXKyEUNGSftB5NUS81ONxfpkTx1utKVzOJEMOGNqH1028N +# gAe4t68/5QohoZq4KR/7ui8bVz6mmzUdO2KVmbFEOX/QBQ7YYnbK0hGGAPBLMAh0 +# HhRxA0E0UInDXeBnkiFS6IiFKhNzopF1LbgXdt3ZpvJrZQLH9ewP6rDhutki2h9v +# PAX9CS9GLn6Cm9aDk8j/Im/GT0hulstL+ZxK9y22eshV5MzqXJtgVsQEubr+oGIF +# +RA1SR38yy7Ak9wTOo3lQ0T3vNwxggHSMIIBzgIBATAxMB0xGzAZBgNVBAMMEkxv +# Y2FsIENvZGUgU2lnbmluZwIQVQoeTLrf5bJKxVZKPVHSEzAJBgUrDgMCGgUAoHgw +# GAYKKwYBBAGCNwIBDDEKMAigAoAAoQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGC +# NwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAjBgkqhkiG9w0BCQQx +# FgQULf3QJRKYaFejcPxKTejtfpjOZQkwDQYJKoZIhvcNAQEBBQAEggEAaDfNu3W9 +# bBvj1GLLQ28eQGgA4W6NZmtP6ph4Agav9bmD+9wRl7yR71Vzn0vvJc2sRxDS9ASG +# l0axrfSEWYszlFwxJbmg76IEtUP7DB2uAqKegMsOW3MFJcm337xypJYkhnAL1Im4 +# Lo9MKdaNe3BxsFAXVCwqxxZq2bP0n6wSC9AJdQBL04L3RhReP08NpDS+jr7Ar3xl +# WN8AokBj7So/k1hfXBCWfOcgfSXWoz1Cj/+w+s5T9QWt7KFaOQ0s/UoXfivijQ/a +# 5WOa8CdeB89dpFb/mnnIi55dlt4uazJqEsWjKBzdUUqanCLHD4+z/Dy21oIsgpVE +# DGwOO3jiLSoiWg== +# SIG # End signature block diff --git a/HomeDrive.bat b/HomeDrive.bat new file mode 100644 index 0000000..c89acb3 --- /dev/null +++ b/HomeDrive.bat @@ -0,0 +1 @@ +powershell.exe -ExecutionPolicy Unrestricted -File .\HomeDrive.ps1 \ No newline at end of file diff --git a/HomeDrive.ps1 b/HomeDrive.ps1 new file mode 100644 index 0000000..2f512d1 --- /dev/null +++ b/HomeDrive.ps1 @@ -0,0 +1,37 @@ +try +{ + $Filter = "(samaccountname=$env:username)" + $RootOU = "dc=nd,dc=gov" + + Write-Warning $Filter + + $Searcher = New-Object DirectoryServices.DirectorySearcher + $Searcher.Filter = $Filter + $result=$Searcher.FindAll() + + $homedir = $result.properties.homedirectory + $homedrive = $result.properties.homedrive + $ScriptPath = $result.properties.scriptpath + + Write-Warning ("HomeDirectory: " + $homedir ) + Write-Warning ("HomeDrive: " + $homedrive) + + If($homedrive) + { + New-PSDrive -Name $homedrive.TrimEnd(':') -PSProvider FileSystem -Root $homedir -Persist + } + + If($ScriptPath) + { + Write-Warning ("ScriptPath: " + $ScriptPath) + $LoginScript = "\\nd.gov\netlogon\$ScriptPath" + Start-Process "cmd.exe" "/c $loginscript" #<< run loginscript + } +} +catch +{ + New-Item -Path "$env:userprofile\Desktop\MapDrivesError.txt" + $error | Set-Content .\MapDrivesError.txt +} + +Read-Host -Prompt "Press Enter to complete" \ No newline at end of file diff --git a/HomeDriveNoSign.ps1 b/HomeDriveNoSign.ps1 new file mode 100644 index 0000000..7e6a340 --- /dev/null +++ b/HomeDriveNoSign.ps1 @@ -0,0 +1,24 @@ +$Filter = "(samaccountname=$env:username)" +$RootOU = "dc=nd,dc=gov" + +Write-Warning $Filter + +$Searcher = New-Object DirectoryServices.DirectorySearcher +$Searcher.Filter = $Filter +$result=$Searcher.FindAll() + +$homedir = $result.properties.homedirectory +$homedrive = $result.properties.homedrive +$ScriptPath = $result.properties.scriptpath + +If($ScriptPath) +{ + $LoginScript = "\\nd.gov\netlogon\$ScriptPath" + Start-Process "cmd.exe" "/c $loginscript" #<< run loginscript +} + +If($homedrive) +{ + New-PSDrive -Name $homedrive.TrimEnd(':') -PSProvider FileSystem -Root $homedir -Persist +} + diff --git a/IIS-Logs.ps1 b/IIS-Logs.ps1 new file mode 100644 index 0000000..5a8de62 --- /dev/null +++ b/IIS-Logs.ps1 @@ -0,0 +1,454 @@ +$IISservers = @" +DHSSOSRVLNAPP +DHSSOSRVLNHUB +DOTSERVER3 +ITDANDCONT2 +ITDAPP11 +ITDAPP12 +ITDAPP7 +ITDAPP8 +ITDAPPSCANENT +ITDAPV +ITDASR1 +ITDASR2 +ITDAUDIT1 +itdbzprod1 +ITDCA5 +ITDCA6 +ITDCC2 +ITDCDEWEB +ITDCDEWEB1 +ITDCITRIXLIC +ITDCJISNETP1 +ITDCJISNETT1 +ITDCJISNETT2 +ITDCJISSQLP1 +ITDCJISSQLT1 +ITDCLOUDNET1 +ITDCLOUDNETP1 +ITDCLOUDNETP2 +ITDCLOUDNETP3 +ITDCLOUDNETT2 +ITDCLOUDNETTRN1 +ITDCNDHEBOOKS1 +ITDCNDHEFRDP10 +ITDCNDHEFRDP6 +ITDCNDHEHRDP1 +ITDCNDHEHRDP7 +ITDCNDHEUPK1 +ITDCNDHEURDP1 +ITDCNDSTBOOKS1 +ITDCNDSTFRDP4 +ITDCNDSTFRDP6 +ITDCNDSTHQWT +ITDCNDSTHRDP6 +ITDCNDSTLRDP6 +ITDCNDSTLSCORM1 +ITDCNDSTRDP855 +ITDCNDSTRRDP6 +ITDCNDSTRWP +ITDCNDSTUPK1 +ITDCNDSTURDP1 +ITDCOG11TST +ITDCOGENTDEV +ITDCOGENTPRD1 +ITDCOGENTPRD2 +ITDCOGENTPUB +ITDCOGENTTST +ITDCOGMMISPRM +ITDCOGMMISPRM2 +ITDCOGMMISSIT +ITDCOGMMISTRN +ITDCOGMMISUAT +ITDCOGNDUS +ITDCOMPLIANCE1 +ITDCOMPLIANCE2 +ITDCRMP1 +ITDCRMP2 +ITDDEQAPPP1 +ITDDEQAPPT1 +ITDDEQNETP1 +ITDDEQNETT1 +ITDDESNETP1 +ITDDESNETT1 +ITDDEVOS +ITDDFSP1 +itddhsawarepz1 +itddhsawaretz1 +ITDDHSMIDMZP1 +ITDDHSMIDMZT1 +ITDDHSMIRRIMGP1 +ITDDHSMIRRIMGT1 +ITDDHSPYXCCEP1 +ITDDHSPYXCCET1 +ITDDHSPYXESP1 +ITDDHSPYXEST1 +ITDDHSQMSP1 +ITDDHSQMST1 +ITDDLMACPT1 +ITDDLMDEV1 +ITDDLMPRTPROD +ITDDLMSIT1 +ITDDLMTRNG1 +ITDDLMUAT1 +itddmrdmscnv +itddmrdmspfta +itddmrdmspftw +itddmrdmsprda +itddmrdmsprdw +itddmrdmssit +itddmrdmssta +itddmrdmsstw +itddmrdmstrn +itddmrdmsuat +itddmrdmsuit +itddmrdmsutlb +ITDDOCAPPP1 +ITDDOCNETP1 +ITDDOCNETT1 +ITDDOCRCIPS +ITDDOCRRDS +ITDDOHICP1 +ITDDOHIMSP1 +ITDDOHIMST1 +ITDDOHLEGENDP2 +ITDDOHLEGENDP3 +ITDDOHLEGENDT2 +ITDDOHLEGENDT3 +ITDDOHNETP3 +ITDDOHNETT3 +ITDDOHNETT4 +ITDDOHPRSP1 +itddohslimst1 +ITDDOHVID +ITDDOTAPPT1 +ITDDOTATMSQ1 +ITDDOTDTIMSP1 +ITDDOTDTIMST1 +ITDDOTEXTDSAIIS +ITDDOTFCR1 +ITDDOTFLEETP1 +ITDDOTFLEETT1 +ITDDOTFRSQL1 +ITDDOTGISWEB +ITDDOTGISWEB2 +ITDDOTGISWEB3 +ITDDOTHEAT +ITDDOTINTDSAIIS +ITDDOTMVP1 +ITDDOTMVP2 +ITDDOTMVP3 +ITDDOTMVS2 +ITDDOTMVS3 +ITDDOTNAS3 +ITDDOTNETEP1 +ITDDOTNETET1 +ITDDOTNETP1 +ITDDOTNETT1 +ITDDOTNETT2 +ITDDOTRTP1 +ITDDOTRTT1 +ITDDOTSCCM12 +ITDDOTSERVER4 +ITDDOTSTS +ITDDOTTFSP1 +itddottrvltmp1 +ITDDOTUNI3 +ITDDOTUNI4 +ITDDPA1 +ITDDPINETT1 +ITDDPISAARP1 +ITDDPISAARP2 +ITDDPISAART1 +ITDDPISAART2 +ITDECAS2 +ITDERNSAG1 +ITDERNSAG10 +ITDERNSAG12 +ITDERNSAG13 +ITDERNSAG2 +ITDERNSAG3 +ITDERNSAG4 +ITDERNSAG5 +ITDERNSAG6 +ITDERNSAG7 +ITDERNSAG8 +ITDERNSAG9 +ITDEXCHCASBIS1 +ITDEXCHCASMAN1 +ITDEXCHMBXBIS1 +ITDEXCHMBXBIS2 +ITDEXCHMBXMAN1 +ITDEXCHMBXMAN2 +ITDEXCHT1 +ITDEXCHT2 +ITDFUSION +ITDGEOLYNX1 +ITDGEOLYNX2 +ITDGISUTILITY +ITDGNFCODY2 +ITDGNFGEO1 +ITDHEATDEV1 +ITDHEATPROD1 +ITDHEATT1 +ITDHPNEARP1 +ITDHPNEARP2 +ITDHPNEARP3 +ITDHPNEARP4 +ITDHPNEART1 +ITDHPNEART2 +ITDILAPP1 +ITDILAPP1TST +ITDILEF1 +ITDILEF1TST +ITDILEM1 +ITDILEM1TST +ITDILWEB1 +ITDILWEB1TST +ITDILWEB2 +ITDILWEB2TST +ITDJSNABSUITEP1 +ITDJSNABSUITEP2 +ITDJSNLDAPC +ITDJSNUIP1 +ITDJSNUIT1 +ITDK12ADFS1 +ITDK12ADFS2 +ITDK12ADFSD1 +ITDK12ADFSPROXY +ITDK12ADFSS1 +ITDK12FIMPTL1 +ITDK12FIMPTL2 +ITDK12FIMPTLS1 +ITDK12FIMPTLS2 +itdk12vpointweb +ITDLANSWEEPER +ITDLIST +ITDLISTDEV +ITDLOCALITY +ITDMBAM1 +ITDMFA1 +ITDMFA2 +ITDMFA3 +ITDMFAPORTAL1 +ITDMFASERVER1 +ITDMFASQL1 +ITDMFASQL2 +ITDMFAT1 +ITDMFAVPNAGENT1 +ITDMFAVPNAGENT2 +ITDMIDMZT1 +ITDMIGATEWAY +ITDMIGATEWAYT1 +ITDMITRANSFERP1 +ITDMMISTMART +ITDNADEFENDP1 +ITDNANFSTEST +itdnbaio +itdnbweb1 +ITDNET35P1 +ITDNET35P2 +ITDNET35T1 +ITDNET35T2 +ITDNETP1 +ITDNETP2 +ITDNETP4 +ITDNETT1 +ITDNETT2 +ITDNETT4 +ITDNETU2 +ITDNPS2 +ITDOMBNETP1 +ITDOMBNETT1 +ITDOMBWR +ITDOPENSCAN1 +ITDOPENSCAN1TST +ITDOPENSCAN2 +ITDOUTMAN1 +ITDOWAPPTEST +ITDOWAPROD +ITDPAESMEXT1 +ITDPAESMINT1 +ITDPREMIERP1 +ITDPREMIERP2 +ITDPREMIERSQLT1 +ITDPREMIERT1 +ITDPREMIERTRN1 +ITDPS-IMAGES +ITDPS-UPDATE +ITDPV2 +ITDPVTEST +ITDPWDSG +ITDRATRPT2 +ITDRATRPT3 +ITDRATRPT4 +ITDRFAX +itdrpaorchp1 +itdrpaorcht1 +ITDRRISYNERGY +itdsaoicp1 +ITDSCCM1 +ITDSCCM1REPORT +ITDSCCMP2 +ITDSCCMP2MAC1 +ITDSCCMUP1 +ITDSCCMWSUS1 +ITDSCCMWSUSUP1 +ITDSHSAPPS +ITDSHSPRESRVP1 +ITDSITXPR4 +ITDSKYPEBIS1 +ITDSKYPEBIS2 +ITDSKYPEDIR1 +ITDSKYPEEDGE1 +ITDSKYPEEDGET1 +ITDSKYPEFET1 +ITDSKYPEMAN1 +ITDSKYPEMAN2 +ITDSLDSMLDE +ITDSLDSSPPROD2 +ITDSLEDD1HE +ITDSLEDD1K12 +ITDSLRWNDS +ITDSLRWNDSTEST +ITDSOSBLSAPPP1 +ITDSOSBLSAPPT1 +ITDSOSBLSWEBP1 +ITDSOSBLSWEBT1 +ITDSOSBPIWP1 +ITDSOSBPIWP2 +ITDSOSBPWT1 +ITDSOSBPWT2 +ITDSOSINDEXP1 +ITDSOSINDEXP2 +ITDSOSINDEXT1 +ITDSOSINDEXTRN1 +ITDSOSVIPP1 +ITDSOSVIPP2 +ITDSOSVIPT1 +ITDSOSVOICESP1 +ITDSOSVOICESP2 +ITDSOSVOICEST1 +ITDSPDEVK12TST +ITDSPSLDSPROD +ITDSPSPROD +ITDSPSPROD1DR13 +ITDSPSPRODSERV +ITDSPSTEST +ITDSTORADMIN3 +ITDTAXAPPP2 +ITDTEAMP1 +ITDTEAMT1 +ITDTESTDEVCA6 +ITDTEXCAS1 +ITDTEXCAS2 +ITDTEXMBX1 +ITDTEXMBX2 +ITDTFSP2 +ITDTFSP3 +ITDTFSSPPROD +ITDTFST2 +ITDTRVPHRAPP1 +ITDTRVPHRGW +ITDTSKYPEFE1 +ITDTSKYPEFE2 +ITDTSKYPEFE3 +ITDTSKYPEFE4 +ITDVMVCP1SCRIPT +ITDVMVCP2SCRIPT +ITDVMVRAIAASP1 +ITDVMVRAIAAST1 +ITDWSIEXTAPPC1 +ITDWSIEXTAPPC2 +ITDWSIEXTAPPD1 +ITDWSIEXTAPPP1 +ITDWSIEXTAPPP2 +ITDWSIEXTAPPT1 +ITDWSIEXTAPPT2 +ITDWSIEXTSQLT1 +ITDWSIEXTSRVP1 +ITDWSIEXTSRVT1 +ITDWSIITSM +ITDWSINETP1 +ITDWSINETT1 +ITDWSINETT2 +ITDWSIPRDWEB01 +ITDWSITESTCERT1 +ITDWSITESTDEVM1 +ITDWSITESTDEVR1 +ITDWSITESTSYS01 +ITDWSITESTUAT01 +ITDWSSPROD +ITDWSSTEST +ITDWSUS +ITDWWW10 +ITDWWW11 +ITDWWW12 +ITDWWW3 +ITDWWW7 +ITDWWW8 +ITDWWW9 +itdwwwdev10 +ITDWWWDEV3 +ITDWWWDEV7 +ITDWWWDEV8 +ITDWWWDEV9 +NODAK00 +NODAK02 +NODAK04 +WSIAPP1 +"@ + +$servers = ConvertTo-Array -MultiLineString $IISservers +$result = @() +$func = { + try { + Import-Module WebAdministration + #$result=@() + $sites = Get-ChildItem IIS:\Sites\ + ForEach ($site in $sites) { + $id = $site.id + $logdir = $site.logfile.directory + "\w3svc" + $id + If ($logdir -like "*%SystemDrive%*") { + $location = $site.logfile.directory -replace '%SystemDrive%', 'C:' + } + else { + $Location = $logdir + } + $LogFilesAll = Get-ChildItem $location -Recurse + $LogFiles15D = $LogFilesAll | Where-Object LastWriteTime -lt ((Get-Date).AddDays(-15)) + $LogFiles30D = $LogFilesAll | Where-Object LastWriteTime -lt ((Get-Date).AddDays(-30)) + $LogFiles60D = $LogFilesAll | Where-Object LastWriteTime -lt ((Get-Date).AddDays(-60)) + $LogFiles90D = $LogFilesAll | Where-Object LastWriteTime -lt ((Get-Date).AddDays(-90)) + $OldestDate = ($LogFilesAll | Sort-Object LastWriteTime | Select-Object -First 1).LastWriteTime + + + + $obj = [PSCustomObject]@{ + SiteName = $site.Name; + LogDir = $location; + LogsAll = [math]::round(($LogFilesAll | measure-object -sum length).sum/1MB, 2); + Logs15D = [math]::round(($LogFiles15D | measure-object -sum length).sum/1MB, 2); + Logs30D = [math]::round(($LogFiles30D | measure-object -sum length).sum/1MB, 2); + Logs60D = [math]::round(($LogFiles60D | measure-object -sum length).sum/1MB, 2); + Logs90D = [math]::round(($LogFiles90D | measure-object -sum length).sum/1MB, 2); + OldestFile = $OldestDate; + } + $obj + } + } + catch { + + } +} + +$result = Invoke-Command -Credential $AdminCred -ScriptBlock $func -ComputerName $servers + + + +$funcCleanup = { + Get-Childitem -Path $args[0] | Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-$args[1]) } +} +ForEach ($site in $result) { + Invoke-Command -ComputerName $site.PSComputerName -ScriptBlock $funcCleanup -Credential $AdminCred -ArgumentList $site.PSComputerName, $site.LogDir, 90 +} \ No newline at end of file diff --git a/ITDAzHybridWorker.zip b/ITDAzHybridWorker.zip new file mode 100644 index 0000000000000000000000000000000000000000..8f85e13cca4d1f91eb20cc9454e9a931084be236 GIT binary patch literal 1800 zcmb7_X*3&%7RN)ZU1p+@;XnG@&J`sv?4@?Vv5y*q$mCBE&W* zwNFW7sU>K1Nobj>H8r)AiY-&IyuA12b>5jT@7{CIz4zR6|M$y1=ZA6tN`V1#VrP)s zP=N0YBChQ&{lhBCHqwU_fWI6}3iKlx5<~GOuP);*@~y$K!rB&BSp2?08xQhxo;_4y z6e&qL`em~wZSHlna)XUE5ME>3h_Js>j08TI;=w=v2F&`tqJlp}d)fnL_!7i4!5afh+j2 zsd@UUXZ`|_^ZQm;vx5D@TU81prIh4PK*y~3dQ+*2yX!~ISI>UUV`4reMubM>?B5Rt zcDkY84N_bN9%sx0V?R!W{9!0Ftc*ld)p*j!Iupuh z(cUi`OGBKog19liQTK>7>nEwc^Z=i8`A3zg;oBeEF%Q4;g1CAQ$mP+=WTB?C!sQGqxry7l%%04)KCV>&;xYk_&f?k+FIUnN5KB{l%Id`&F zZh))Tna`kj;ABqIMsn>P8Z*%HoR?)kvrp#}bA^@TjycbF!CzW=ih65r62zbLHig-w z-Ls(e0GY0GDH9T+oLGpzNq>NtGH+n1&ONn@XiO^6}{=YAoFGyuWK4`l#- z?qOwEP|EO$=+3A8FJ5ATWSSdM{kxbkATIUodm{~+Z*lcR2iIp`EE3*0*z0;>g}Imh zXYJxpOQ8O`w0>IG=Gtnqa@b-g<6l`q^`TFxi+Dm6j5fg8YBpl?q48+7xeKa~+-F>y~T1sT2-`nJZ|Q(-%`kiF;Oe;bV!Cgh_|gg5(zB&=DcLj_LpWwvy?e;8BC)$D(FEJ?bVeh6#~iQ)cS5 z+2N@8v(6cj;EL#_nA?zFL&MZ&S$L2<>cB}QD&H7W4DG`$TgRsKZp)p-cU_E`D?Gt( z4$tp=ET=h9%o8~s+!Dlgm$Tf`E6)48*y21|o8{Ks| zVB}R--ZL@G0%cgZICFjMw!)Hvc^k3$yxKX97{>i^YOT*HwxX!(NlqKcXo=C&DLiRL zWBW5257BKR+I0pdQ4X?l!H|1FlhOcyHV6Pf{ojZPGI5g;ugS{o(fx=(F-IiCfpUBy6zbDWCYJ9K%SB+ybe^0L<6O@Crcm@DSialAJZ~mwI7n)*1&;S4c literal 0 HcmV?d00001 diff --git a/KMS-LicensingEventLog.ps1 b/KMS-LicensingEventLog.ps1 new file mode 100644 index 0000000..13af9d5 --- /dev/null +++ b/KMS-LicensingEventLog.ps1 @@ -0,0 +1,48 @@ +$InvokeResult = Invoke-Command -ComputerName itdkms3.nd.gov -Credential $PrvCred -ScriptBlock { + Get-WinEvent -LogName "Key Management Service" -MaxEvents 100000 | Select-Object TimeCreated, ` + @{n='Hostname';e={$_.Message.Split("`n")[2].Split(',')[2]}}, ` + @{n='ErrorCode';e={$_.Message.Split("`n")[2].Split(',')[0]}}, ` + @{n='FullEntry';e={$_.Message.Split("`n")[2]}}, ` + @{n='ActivationID';e={$_.Message.Split("`n")[2].Split(',')[8]}}, ` + @{n='ProductName';e={ + switch ($_.Message.Split("`n")[2].Split(',')[8]) { + 'de32eafd-aaee-4662-9444-c1befb41bde2' { "Windows Server 2019 Standard" } + '34e1ae55-27f8-4950-8877-7a03be5fb181' { "Windows Server 2019 Datacenter" } + '8c1c5410-9f39-4805-8c9d-63a07706358f' { "Windows Server 2016 Standard" } + 'b3ca044e-a358-4d68-9883-aaa2941aca99' { "Windows Server 2012R2 Standard" } + '73111121-5638-40f6-bc11-f1d7b0d64300' { "Windows 10 Enterprise" } + 'd450596f-894d-49e0-966a-fd39ed4c4c64' { "Office 16, Office16ProPlusVL_KMS_Client edition" } + 'b234abe3-0857-4f9c-b05a-4dc314f85557' { "Visio or Project 2016 ??" } + '85dd8b5f-eaa4-4af3-a628-cce9e77c9a03' { "Office 20xx C2R (deployed spring 2022 on Servers)" } + '21c56779-b449-4d20-adfc-eece0e1ad74b' { "Windows Server 2016 Datacenter"} + 'e13ac10e-75d0-4aff-a0cd-764982cf541c' { "Visio or Project 2013 ??"} + 'b13afb38-cd79-4ae5-9f7f-eed058d750ca' { "Office15 / Office Standard 2013 ??"} + '32d2fab3-e4a8-42c2-923b-4bf4fd13e6ee' { "Windows 10 Enterprise LTSC 2021 ??"} + '2de67392-b7a7-462a-b1ca-108dd189f588' { "Windows 10 Pro"} + '829b8110-0e6f-4349-bca4-42803577788d' { "Office16ProjectProXC2RVL_KMS_ClientC2R ??"} + 'b322da9c-a2e2-4058-9e4e-f59a6970bd69' { "Office15 / Office 2013 Professional Plus"} + 'dedfa23d-6ed1-45a6-85dc-63cae0546de6' { "Office16StandardVL_KMS_Client"} + Default { "" } + } + }} | sort-object TimeCreated -Descending } + + + + $InvokeResult | export-csv "D:\itdkms3-log.csv" + +<# +Run +Get-WMIObject -Class SoftwareLicensingProduct +on client device to determine which software is which activation ID + +Windows Server 2019 Standard - de32eafd-aaee-4662-9444-c1befb41bde2 +Windows Server 2019 Datacenter - 34e1ae55-27f8-4950-8877-7a03be5fb181 +Windows Server 2016 Standard - 8c1c5410-9f39-4805-8c9d-63a07706358f +Windows Server 2012R2 Standard - b3ca044e-a358-4d68-9883-aaa2941aca99 +Windows 10 Enterprise - 73111121-5638-40f6-bc11-f1d7b0d64300 + +Office 16, Office16ProPlusVL_KMS_Client edition - d450596f-894d-49e0-966a-fd39ed4c4c64 +Visio or Project 2016 ?? - b234abe3-0857-4f9c-b05a-4dc314f85557 +Office 20xx (deployed spring 2022 on Servers) - 85dd8b5f-eaa4-4af3-a628-cce9e77c9a03 + +#> \ No newline at end of file diff --git a/KMS-Office.ps1 b/KMS-Office.ps1 new file mode 100644 index 0000000..d0da3e7 --- /dev/null +++ b/KMS-Office.ps1 @@ -0,0 +1,28 @@ +##### Fix locally, run as admin +Set-Location "C:\Program Files\Microsoft Office\Office16\" # might be a different folder for different versions + +# get current status +cscript .\ospp.vbs /dstatus + +# set KMS server and activate +cscript .\ospp.vbs /sethst:kms.nd.gov +cscript .\ospp.vbs /act + + + +##### Fix remotely, will prompt for PRV credentials +$Credential = Get-Credential -Message "Enter your PRV credentials" + +# Get current status +Invoke-Command -Credential $Credential -ComputerName server01,server02,server03 -ScriptBlock { + Set-Location "C:\Program Files\Microsoft Office\Office16\" + cscript .\ospp.vbs /dstatus +} + + +# Set KMS server and activate +Invoke-Command -Credential $Credential -ComputerName server01,server02,server03 -ScriptBlock { + Set-Location "C:\Program Files\Microsoft Office\Office16\" + cscript .\ospp.vbs /sethst:kms.nd.gov + cscript .\ospp.vbs /act +} diff --git a/KMS-Windows.ps1 b/KMS-Windows.ps1 new file mode 100644 index 0000000..d72cb43 --- /dev/null +++ b/KMS-Windows.ps1 @@ -0,0 +1,25 @@ +##### Fix locally, run as admin (or system) + +# get current status +cscript C:\windows\system32\slmgr.vbs -dli + +# set KMS server and activate +cscript C:\windows\system32\slmgr.vbs -skms kms.nd.gov +cscript C:\windows\system32\slmgr.vbs -ato + + + +##### Fix remotely, will prompt for PRV credentials +$Credential = Get-Credential -Message "Enter your PRV credentials" + +# Get current status +Invoke-Command -Credential $Credential -ComputerName server01,server02,server03 -ScriptBlock { + cscript C:\windows\system32\slmgr.vbs -dli +} + + +# Set KMS server and activate +Invoke-Command -Credential $Credential -ComputerName server01,server02,server03 -ScriptBlock { + cscript C:\windows\system32\slmgr.vbs -skms kms.nd.gov + cscript C:\windows\system32\slmgr.vbs -ato +} diff --git a/Network-ConvertCIDRtoSubnetMask.ps1 b/Network-ConvertCIDRtoSubnetMask.ps1 new file mode 100644 index 0000000..f3243e0 --- /dev/null +++ b/Network-ConvertCIDRtoSubnetMask.ps1 @@ -0,0 +1,45 @@ +Function Convert-RvNetInt64ToIpAddress() +{ + <# + .DESCRIPTION + Developer + Developer: Rudolf Vesely, http://rudolfvesely.com/ + Copyright (c) Rudolf Vesely. All rights reserved + License: Free for private use only + #> + + Param + ( + [int64] + $Int64 + ) + + # Return + '{0}.{1}.{2}.{3}' -f ([math]::Truncate($Int64 / 16777216)).ToString(), + ([math]::Truncate(($Int64 % 16777216) / 65536)).ToString(), + ([math]::Truncate(($Int64 % 65536)/256)).ToString(), + ([math]::Truncate($Int64 % 256)).ToString() +} + +Function Convert-RvNetSubnetMaskCidrToClasses +{ + <# + .DESCRIPTION + Developer + Developer: Rudolf Vesely, http://rudolfvesely.com/ + Copyright (c) Rudolf Vesely. All rights reserved + License: Free for private use only + #> + + Param + ( + [int] + $SubnetMaskCidr + ) + + # Return + Convert-RvNetInt64ToIpAddress -Int64 ([convert]::ToInt64(('1' * $SubnetMaskInt + '0' * (32 - $SubnetMaskInt)), 2)) +} + + +$SubnetMaskInt = 28 diff --git a/Network-VLANCompare.txt b/Network-VLANCompare.txt new file mode 100644 index 0000000..56ea0f7 --- /dev/null +++ b/Network-VLANCompare.txt @@ -0,0 +1,47 @@ +$Switch23996 = Get-Content D:\VLAN-23996.txt +$Switch23997 = Get-Content D:\VLAN-23997.txt +$Switch23998 = Get-Content D:\VLAN-23998.txt +$Switch23999 = Get-Content D:\VLAN-23999.txt + +$VC1PortGroups = Get-VirtualPortGroup -VirtualSwitch "dvSwitch-PDC-Data-Server" +$VC2PortGroups = Get-VirtualPortGroup -VirtualSwitch "dvSwitch-SDC-Data-Server" +$AllPortGroups = ($VC1PortGroups + $VC2PortGroups) | select -Unique Name | Sort-Object Name +$AllVmNetworkAdapters = ((Get-VM | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -ne "placeholderVm" }) | Get-NetworkAdapter) + +$Result = [System.Collections.ArrayList]@() + +ForEach ($PortGroup in $AllPortGroups) { + $obj = $null + $VlanInt = [int]$PortGroup.name.split('_')[1] + $obj = [PSCustomObject]@{ + 'VlanStr' = $PortGroup.name.split('_')[1]; + 'CIDR' = $PortGroup.name.split('_')[2] + '/' + $PortGroup.Name.split('_')[3]; + 'Description' = ($Switch23996 | Where-Object { $_ -like ("*v" + $VlanInt + "*") }).split(' ')[2]; + 'vNic_Count' = ($AllVmNetworkAdapters | where-object NetworkName -like "*$CIDR*").count + + '23996-61' = ($Switch23996 | Where-Object { $_ -like ("*v" + $VlanInt + "*") }).split(' ')[5] -like "*61*" + '23996-69' = ($Switch23996 | Where-Object { $_ -like ("*v" + $VlanInt + "*") }).split(' ')[5] -like "*69*" + '23996-73' = ($Switch23996 | Where-Object { $_ -like ("*v" + $VlanInt + "*") }).split(' ')[5] -like "*73*" + '23996-81' = ($Switch23996 | Where-Object { $_ -like ("*v" + $VlanInt + "*") }).split(' ')[5] -like "*81*" + '23996-89' = ($Switch23996 | Where-Object { $_ -like ("*v" + $VlanInt + "*") }).split(' ')[5] -like "*89*" + + '23997-61' = ($Switch23997 | Where-Object { $_ -like ("*v" + $VlanInt + "*") }).split(' ')[5] -like "*61*" + '23997-69' = ($Switch23997 | Where-Object { $_ -like ("*v" + $VlanInt + "*") }).split(' ')[5] -like "*69*" + '23997-73' = ($Switch23997 | Where-Object { $_ -like ("*v" + $VlanInt + "*") }).split(' ')[5] -like "*73*" + '23997-81' = ($Switch23997 | Where-Object { $_ -like ("*v" + $VlanInt + "*") }).split(' ')[5] -like "*81*" + '23997-89' = ($Switch23997 | Where-Object { $_ -like ("*v" + $VlanInt + "*") }).split(' ')[5] -like "*89*" + + '23998-61' = ($Switch23998 | Where-Object { $_ -like ("*v" + $VlanInt + "*") }).split(' ')[5] -like "*61*" + '23998-69' = ($Switch23998 | Where-Object { $_ -like ("*v" + $VlanInt + "*") }).split(' ')[5] -like "*69*" + '23998-81' = ($Switch23998 | Where-Object { $_ -like ("*v" + $VlanInt + "*") }).split(' ')[5] -like "*81*" + '23998-89' = ($Switch23998 | Where-Object { $_ -like ("*v" + $VlanInt + "*") }).split(' ')[5] -like "*89*" + + '23999-61' = ($Switch23999 | Where-Object { $_ -like ("*v" + $VlanInt + "*") }).split(' ')[5] -like "*61*" + '23999-69' = ($Switch23999 | Where-Object { $_ -like ("*v" + $VlanInt + "*") }).split(' ')[5] -like "*69*" + '23999-81' = ($Switch23999 | Where-Object { $_ -like ("*v" + $VlanInt + "*") }).split(' ')[5] -like "*81*" + '23999-89' = ($Switch23999 | Where-Object { $_ -like ("*v" + $VlanInt + "*") }).split(' ')[5] -like "*89*" +} + +#Write-Output $obj +$null = $Result.Add($obj) +} \ No newline at end of file diff --git a/PSObject with Properties.ps1 b/PSObject with Properties.ps1 new file mode 100644 index 0000000..b791c93 --- /dev/null +++ b/PSObject with Properties.ps1 @@ -0,0 +1,46 @@ +<# +.Synopsis + Short description +.DESCRIPTION + Long description +.EXAMPLE + Example of how to use this cmdlet +.EXAMPLE + Another example of how to use this cmdlet +#> +function Get-PropertyObjectTest +{ + [CmdletBinding()] + Param + ( + [string[]] + $ProcessName + ) + + Begin + { + } + Process + { + $MyArrayList = [System.Collections.ArrayList]@() + $null = $MyArrayList.Add($obj) + ForEach ($Process in $ProcessName) + { + $Output = Get-Process -Name $Process + + $obj=[PSCustomObject]@{ + 'ProcessName' = $Output.Name; + 'CPU' = $Output.CPU -as [int]; + 'VMGB' = $Output.VirtualMemorySize64 / 1GB -as [int]; + 'WSMB' = $Output.WorkingSet64 / 1MB -as [int]; + } + + #Write-Output $obj + $null = $MyArrayList.Add($obj) + } + } + End + { + } +} + diff --git a/PSRepo-Features.ps1 b/PSRepo-Features.ps1 new file mode 100644 index 0000000..02d7296 --- /dev/null +++ b/PSRepo-Features.ps1 @@ -0,0 +1,38 @@ + +FileAndStorage-Services +Storage-Services +Web-Server +Web-WebServer +Web-Common-Http +Web-Default-Doc +Web-Dir-Browsing +Web-Http-Errors +Web-Static-Content +Web-Health +Web-Http-Logging +Web-Performance +Web-Stat-Compression +Web-Security +Web-Filtering +Web-App-Dev +Web-Net-Ext45 +Web-Asp-Net45 +Web-ISAPI-Ext +Web-ISAPI-Filter +Web-Mgmt-Tools +Web-Mgmt-Console +NET-Framework-45-Features +NET-Framework-45-Core +NET-Framework-45-ASPNET +NET-WCF-Services45 +NET-WCF-TCP-PortSharing45 +RDC +System-DataArchiver +Windows-Defender +PowerShellRoot +PowerShell +PowerShell-ISE +WoW64-Support +XPS-Viewer + + diff --git a/PackageManagementInstall/Step1-CopyDll.ps1 b/PackageManagementInstall/Step1-CopyDll.ps1 new file mode 100644 index 0000000..a7c8753 --- /dev/null +++ b/PackageManagementInstall/Step1-CopyDll.ps1 @@ -0,0 +1,8 @@ +#Step 1 - Copy dll +If(!(Test-Path 'C:\Program Files\PackageManagement\ProviderAssemblies\nuget\2.8.5.208\')) +{ + New-Item -Path 'C:\Program Files\PackageManagement\ProviderAssemblies\nuget\2.8.5.208\' -ItemType Directory -Force +} + +Copy-Item -Path '\\itdsccmp2.nd.gov\PowerShell_Repository\Microsoft.PackageManagement.NuGetProvider.dll' -Destination 'C:\Program Files\PackageManagement\ProviderAssemblies\nuget\2.8.5.208\Microsoft.PackageManagement.NuGetProvider.dll' -Force +Exit \ No newline at end of file diff --git a/PackageManagementInstall/Step2-RegPSRepo,InstallModules,CreateSchedule.ps1 b/PackageManagementInstall/Step2-RegPSRepo,InstallModules,CreateSchedule.ps1 new file mode 100644 index 0000000..4b20731 --- /dev/null +++ b/PackageManagementInstall/Step2-RegPSRepo,InstallModules,CreateSchedule.ps1 @@ -0,0 +1,3 @@ +# Step 2 RegisterPSRepo / Install Newest Modules +Register-PSRepository -Name "NDGOV_SCCM" -SourceLocation "\\itdsccmp2.nd.gov\PowerShell_Repository" -PublishLocation "\\itdsccmp2.nd.gov\PowerShell_Repository" -InstallationPolicy Trusted -PackageManagementProvider nuget + diff --git a/PackageManagementInstall/Step3-Install Modules.ps1 b/PackageManagementInstall/Step3-Install Modules.ps1 new file mode 100644 index 0000000..46461da --- /dev/null +++ b/PackageManagementInstall/Step3-Install Modules.ps1 @@ -0,0 +1,2 @@ +# Step 3 Install Modules +Find-Module ITD.Global,ITD.Windows -Repository NDGOV_SCCM | Install-Module \ No newline at end of file diff --git a/PackageManagementInstall/Step4-ExpiredFilesDefaultConfig.ps1 b/PackageManagementInstall/Step4-ExpiredFilesDefaultConfig.ps1 new file mode 100644 index 0000000..e9a8ac0 --- /dev/null +++ b/PackageManagementInstall/Step4-ExpiredFilesDefaultConfig.ps1 @@ -0,0 +1,2 @@ +New-ITDExpiredFilesSchedule +New-ITDExpiredFilesJSON \ No newline at end of file diff --git a/PasswordstateWinAPI.ps1 b/PasswordstateWinAPI.ps1 new file mode 100644 index 0000000..4905fa2 --- /dev/null +++ b/PasswordstateWinAPI.ps1 @@ -0,0 +1,36 @@ +Invoke-RestMethod -Method Post -Uri "https://itdpv.nd.gov/api/passwords" -ContentType "application/json" -Body $PasswordJson + + + +Invoke-RestMethod -Method Get -Uri 'https://itdpv.nd.gov/winapi/passwords/20841' -Credential $PrvCred + +$Uri = 'https://itdpv.nd.gov/winapi/searchpasswords/?search=zm' +$x=Invoke-RestMethod -Method Get -Uri $Uri -Credential $PrvCred + + + +$Uri = 'https://itdpv.nd.gov/winapi/passwordlists/377' +Invoke-RestMethod -Method Get -Uri $Uri -Credential $PrvCred + + + +# Retrieving password +$PasswordstateUrl = 'https://itdpv.nd.gov/winapi/passwords/18824' +Invoke-Restmethod -Method GET -Uri $PasswordstateUrl -Credential $PrvCred + +# search for password +$Uri = 'https://itdpv.nd.gov/winapi/searchpasswords/?search=M365' +Invoke-RestMethod -Method Get -Uri $Uri -Credential $PrvCred + +# adding a password +$jsonData = ' + { + "PasswordListID":"53", + "Title":"itdzmbuild01.nd.gov", + "UserName":"test", + "password":"TESTpass12#$%" + } + ' + + $PasswordstateUrl = 'https://itdpv.nd.gov/winapi/passwords' + $result = Invoke-Restmethod -Method Post -Uri $PasswordstateUrl -ContentType "application/json" -Body $jsonData -Credential $PrvCred \ No newline at end of file diff --git a/Register-ADOPSRepo.ps1 b/Register-ADOPSRepo.ps1 new file mode 100644 index 0000000..635594c --- /dev/null +++ b/Register-ADOPSRepo.ps1 @@ -0,0 +1,8 @@ +#Register-PSRepository -Name NDGOV -SourceLocation 'https://ndgov.pkgs.visualstudio.com/_packaging/ITD3/nuget/v2' -PublishLocation 'https://ndgov.pkgs.visualstudio.com/_packaging/ITD3/nuget/v2' -InstallationPolicy Trusted -Credential $AdoCred + + + +Register-PSRepository -Name ITD_PwshGallery ` + -SourceLocation "https://powershell.nd.gov/ITD_PwshGallery/nuget/" ` + -PublishLocation "https://powershell.nd.gov/ITD_PwshGallery/nuget/" ` + -InstallationPolicy Trusted \ No newline at end of file diff --git a/Remove-ITDTempFiles.ps1 b/Remove-ITDTempFiles.ps1 new file mode 100644 index 0000000..4e25a07 --- /dev/null +++ b/Remove-ITDTempFiles.ps1 @@ -0,0 +1,11 @@ +$ImportCsv = Import-Csv -Path 'D:\OneDrive - State of North Dakota\CleanupFileLocations.csv' + +$FilesToDelete=@() +ForEach($Directory in $ImportCsv) { + $GetChildItemParams = @{ + Path = $Directory.Path + } + If($Directory.Filter){$GetChildItemParams += @{Filter = $Directory.Filter}} + If($Directory.Recursive -eq $true){$GetChildItemParams += @{Recurse = $true}} + $Files = Get-ChildItem @GetChildItemParams | Where-Object LastWriteTime -lt (Get-Date).AddDays(-$Directory.DaysToKeep) +} \ No newline at end of file diff --git a/SCCM-AutomationDashboard.ps1 b/SCCM-AutomationDashboard.ps1 new file mode 100644 index 0000000..8ebed42 --- /dev/null +++ b/SCCM-AutomationDashboard.ps1 @@ -0,0 +1,34 @@ +$func = { + Import-Module "D:\Program Files\Microsoft Configuration Manager\AdminConsole\bin\ConfigurationManager.psd1" + Set-Location ITD:\ + + switch ((Get-Date).Day) { + { $_ -ge 10 -and $_ -le 19 } { + $CollectionName = 'All-MW-Monthly, 1st Thursday After 2nd Tuesday' + $Platform = 'Test' + } + { $_ -ge 20 -and $_ -le 31 } { + $CollectionName = 'All-MW-Monthly, 2nd Sunday After 2nd Tuesday' + $Platform = 'Production' + } + Default { + $CollectionName = $null + Exit + } + } + + $PlatformStr = "SCCM-MicrosoftUpdates-" + $Platform + "Servers" + + Get-CMDevice -CollectionName $CollectionName | Select-Object Name, @{n = 'DashboardPlatform'; e = { $PlatformStr } } +} + +$servers = (Invoke-Command -ScriptBlock $func -ComputerName itdsccmp2.nd.gov -Credential $PrvCred) + +$postParams = [PSCustomObject]@{ + AutomationName = "Infra-Servers-SCCM"; + Action = "Patching"; + Units = [int][math]::round($servers.count * 7, 0); + Platform = ($servers | Select-Object -First 1).DashboardPlatform; +} + +Invoke-RestMethod -Uri http://itdnettools.nd.gov/services/automation-tracking.py -Method POST -Body ($postParams | ConvertTo-Json) diff --git a/SCCM-ESUDiscoveryY2.ps1 b/SCCM-ESUDiscoveryY2.ps1 new file mode 100644 index 0000000..0bcab89 --- /dev/null +++ b/SCCM-ESUDiscoveryY2.ps1 @@ -0,0 +1,97 @@ +#MAK & ESU discovery v2 + +$Esu1Bool = $false +$Esu2Bool = $false +$MakBool = $false + +$OS = (Get-WMIObject Win32_OperatingSystem).Caption +Write-Verbose $OS + +switch ($OS) { + 'Microsoft Windows Server 2008 R2 Datacenter ' { + write-verbose "switch datacenter edition" + $MakId = '4ae528f4-05c3-446e-90ea-a4fbd460b83a' + $MakKey = 'MF2F8-YGGFX-6MKDF-PCM29-7BYDG' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' #activationid + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + } + 'Microsoft Windows Server 2008 R2 Enterprise ' { + write-verbose "switch enterprise edition" + $MakId = '6a4bd364-4b60-4856-a727-efb59d94348e' + $MakKey = '3YY4J-742QP-GPKP9-G2R6W-K6DDM' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + } + 'Microsoft Windows Server 2008 R2 Standard ' { + write-verbose "switch standard edition" + $MakId = '' + $MakKey = '3YY4J-742QP-GPKP9-G2R6W-K6DDM' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + } + 'Microsoft Windows 7 Enterprise ' { + write-verbose "switch Win7 enterprise edition" + $MakId = '9abf5984-9c16-46f2-ad1e-7fe15931a8dd' + $MakKey = 'PRV3H-98HJK-6KKBF-RHYTM-JWCRV' + $Esu1Id = '77db037b-95c3-48d7-a3ab-a9c6d41093e0' + $Esu1Key = 'MJCJ8-24DFX-VGK6H-XYBQ7-F6PR8' + $Esu2Id = '0e00c25d-8795-4fb7-9572-3803d91b6880' + $Esu2Key = 'WX34W-WG8MH-TWWCV-PXK96-RDMTJ' + } + 'Microsoft® Windows Server® 2008 Standard ' { + write-verbose "switch 08 Standard" + $MakId = 'ad2542d4-9154-4c6d-8a44-30f11ee96989' + $MakKey = 'GQK9D-CT4WQ-9KJ87-FKMT8-MR73Q' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + } + 'Microsoft® Windows Server® 2008 Enterprise ' { + write-verbose "switch 08 Enterprise" + $MakId = 'bb1d27c4-959d-4f82-b0fd-c02a7be54732' + $MakKey = 'GQK9D-CT4WQ-9KJ87-FKMT8-MR73Q' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + } +} + +$software = Get-WMIObject -Class SoftwareLicensingProduct + +$EsuYear1 = $software | Where-Object { $_.Id -eq $Esu1Id } +If ($EsuYear1) { + If ($EsuYear1.LicenseStatus -eq '1') { + $Esu1Bool = $true + } +} + +$EsuYear2 = $software | Where-Object { $_.Id -eq $Esu2Id } +If ($EsuYear2) { + If ($EsuYear2.LicenseStatus -eq '1') { + $Esu2Bool = $true + } +} + +$Mak = $software | where-object { $_.Id -eq $MakId } +If ($Mak) { + If ($Mak.LicenseStatus -eq 1) { + $MakBool = $true + } +} + +If ($Esu1bool -eq $true -and $Esu2Bool -eq $true -and $Makbool -eq $true) { + $compliant = $true +} +else { + $compliant = $false +} + +$compliant \ No newline at end of file diff --git a/SCCM-ESUDiscoveryY3.ps1 b/SCCM-ESUDiscoveryY3.ps1 new file mode 100644 index 0000000..cad1725 --- /dev/null +++ b/SCCM-ESUDiscoveryY3.ps1 @@ -0,0 +1,121 @@ +#MAK & ESU discovery v3.1 + +$Esu1Bool = $false +$Esu2Bool = $false +$Esu3Bool = $false +$MakBool = $false + +$OS = (Get-WMIObject Win32_OperatingSystem).Caption +Write-Verbose $OS + +switch ($OS) { + 'Microsoft Windows Server 2008 R2 Datacenter ' { + write-verbose "switch datacenter edition" + $MakId = '4ae528f4-05c3-446e-90ea-a4fbd460b83a' + $MakKey = '33YCD-89CD2-RMYVW-RGX7W-R9XRM' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' #activationid + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + $Esu3Id = '16c08c85-0c8b-4009-9b2b-f1f7319e45f9' + $Esu3Key = '36FB4-RK77J-C867T-QPJBT-4PMW6' + } + 'Microsoft Windows Server 2008 R2 Enterprise ' { + write-verbose "switch enterprise edition" + $MakId = '6a4bd364-4b60-4856-a727-efb59d94348e' + $MakKey = 'TB9WQ-WKHVH-W7946-WJTVV-Y6QDD' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + $Esu3Id = '16c08c85-0c8b-4009-9b2b-f1f7319e45f9' + $Esu3Key = '36FB4-RK77J-C867T-QPJBT-4PMW6' + } + 'Microsoft Windows Server 2008 R2 Standard ' { + write-verbose "switch standard edition" + $MakId = '' + $MakKey = 'TB9WQ-WKHVH-W7946-WJTVV-Y6QDD' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + $Esu3Id = '16c08c85-0c8b-4009-9b2b-f1f7319e45f9' + $Esu3Key = '36FB4-RK77J-C867T-QPJBT-4PMW6' + } + 'Microsoft Windows 7 Enterprise ' { + write-verbose "switch Win7 enterprise edition" + $MakId = '9abf5984-9c16-46f2-ad1e-7fe15931a8dd' + $MakKey = 'PRV3H-98HJK-6KKBF-RHYTM-JWCRV' + $Esu1Id = '77db037b-95c3-48d7-a3ab-a9c6d41093e0' + $Esu1Key = 'MJCJ8-24DFX-VGK6H-XYBQ7-F6PR8' + $Esu2Id = '0e00c25d-8795-4fb7-9572-3803d91b6880' + $Esu2Key = 'WX34W-WG8MH-TWWCV-PXK96-RDMTJ' + $Esu3Id = '4220f546-f522-46df-8202-4d07afd26454' + $Esu3Key = 'TF336-89RVD-X2FJJ-YV3KF-Q6KPF' + } + 'Microsoft® Windows Server® 2008 Standard ' { + write-verbose "switch 08 Standard" + $MakId = 'ad2542d4-9154-4c6d-8a44-30f11ee96989' + $MakKey = 'GQK9D-CT4WQ-9KJ87-FKMT8-MR73Q' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + $Esu3Id = '16c08c85-0c8b-4009-9b2b-f1f7319e45f9' + $Esu3Key = '36FB4-RK77J-C867T-QPJBT-4PMW6' + } + 'Microsoft® Windows Server® 2008 Enterprise ' { + write-verbose "switch 08 Enterprise" + $MakId = 'bb1d27c4-959d-4f82-b0fd-c02a7be54732' + $MakKey = 'GQK9D-CT4WQ-9KJ87-FKMT8-MR73Q' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + $Esu3Id = '16c08c85-0c8b-4009-9b2b-f1f7319e45f9' + $Esu3Key = '36FB4-RK77J-C867T-QPJBT-4PMW6' + } +} + +$software = Get-WMIObject -Class SoftwareLicensingProduct + +$EsuYear1 = $software | Where-Object { $_.Id -eq $Esu1Id } +If ($EsuYear1) { + If ($EsuYear1.LicenseStatus -eq '1') { + $Esu1Bool = $true + } +} + +$EsuYear2 = $software | Where-Object { $_.Id -eq $Esu2Id } +If ($EsuYear2) { + If ($EsuYear2.LicenseStatus -eq '1') { + $Esu2Bool = $true + } +} + +$EsuYear3 = $software | Where-Object { $_.Id -eq $Esu3Id } +If ($EsuYear3) { + If ($EsuYear3.LicenseStatus -eq '1') { + $Esu3Bool = $true + } +} + +$Mak = $software | where-object { $_.Id -eq $MakId } +If ($Mak) { + If ($Mak.LicenseStatus -eq 1) { + $MakBool = $true + } +} + +If ($Esu1bool -eq $true -and $Esu2Bool -eq $true -and $Esu3Bool -eq $true -and $Makbool -eq $true) { + $compliant = $true +} +else { + $compliant = $false +} + +$compliant + + +#2008 std/ent TB9WQ-WKHVH-W7946-WJTVV-Y6QDD +#2008 dcntr 33YCD-89CD2-RMYVW-RGX7W-R9XRM \ No newline at end of file diff --git a/SCCM-ESURemediationY2.ps1 b/SCCM-ESURemediationY2.ps1 new file mode 100644 index 0000000..657031b --- /dev/null +++ b/SCCM-ESURemediationY2.ps1 @@ -0,0 +1,68 @@ +#MAK & ESU remediation v2 + +$OS = (Get-WMIObject Win32_OperatingSystem).Caption +write-verbose $OS + +switch ($OS) { + 'Microsoft Windows Server 2008 R2 Datacenter ' { + write-verbose "switch datacenter edition" + $MakId = '4ae528f4-05c3-446e-90ea-a4fbd460b83a' + $MakKey = 'MF2F8-YGGFX-6MKDF-PCM29-7BYDG' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' #activationid + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + } + 'Microsoft Windows Server 2008 R2 Enterprise ' { + write-verbose "switch enterprise edition" + $MakId = '6a4bd364-4b60-4856-a727-efb59d94348e' + $MakKey = '3YY4J-742QP-GPKP9-G2R6W-K6DDM' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + } + 'Microsoft Windows Server 2008 R2 Standard ' { + write-verbose "switch standard edition" + $MakId = '' + $MakKey = '3YY4J-742QP-GPKP9-G2R6W-K6DDM' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + } + 'Microsoft Windows 7 Enterprise ' { + write-verbose "switch Win7 enterprise edition" + $MakId = '9abf5984-9c16-46f2-ad1e-7fe15931a8dd' + $MakKey = 'PRV3H-98HJK-6KKBF-RHYTM-JWCRV' + $Esu1Id = '77db037b-95c3-48d7-a3ab-a9c6d41093e0' + $Esu1Key = 'MJCJ8-24DFX-VGK6H-XYBQ7-F6PR8' + $Esu2Id = '0e00c25d-8795-4fb7-9572-3803d91b6880' + $Esu2Key = 'WX34W-WG8MH-TWWCV-PXK96-RDMTJ' + } + 'Microsoft® Windows Server® 2008 Standard ' { + write-verbose "switch 08 Standard" + $MakId = 'ad2542d4-9154-4c6d-8a44-30f11ee96989' + $MakKey = 'GQK9D-CT4WQ-9KJ87-FKMT8-MR73Q' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + } + 'Microsoft® Windows Server® 2008 Enterprise ' { + write-verbose "switch 08 Enterprise" + $MakId = 'bb1d27c4-959d-4f82-b0fd-c02a7be54732' + $MakKey = 'GQK9D-CT4WQ-9KJ87-FKMT8-MR73Q' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + } +} + +cscript C:\Windows\System32\slmgr.vbs -ipk $MakKey +cscript C:\Windows\System32\slmgr.vbs -ato $MakId +cscript C:\Windows\System32\slmgr.vbs -ipk $Esu1Key +cscript C:\Windows\System32\slmgr.vbs -ato $Esu1Id +cscript C:\Windows\System32\slmgr.vbs -ipk $Esu2Key +cscript C:\Windows\System32\slmgr.vbs -ato $Esu2Id \ No newline at end of file diff --git a/SCCM-ESURemediationY3.ps1 b/SCCM-ESURemediationY3.ps1 new file mode 100644 index 0000000..2ed9b03 --- /dev/null +++ b/SCCM-ESURemediationY3.ps1 @@ -0,0 +1,82 @@ +#MAK & ESU remediation v3.1 + +$OS = (Get-WMIObject Win32_OperatingSystem).Caption +write-verbose $OS + +switch ($OS) { + 'Microsoft Windows Server 2008 R2 Datacenter ' { + write-verbose "switch datacenter edition" + $MakId = '4ae528f4-05c3-446e-90ea-a4fbd460b83a' + $MakKey = '33YCD-89CD2-RMYVW-RGX7W-R9XRM' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' #activationid + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + $Esu3Id = '16c08c85-0c8b-4009-9b2b-f1f7319e45f9' + $Esu3Key = '36FB4-RK77J-C867T-QPJBT-4PMW6' + } + 'Microsoft Windows Server 2008 R2 Enterprise ' { + write-verbose "switch enterprise edition" + $MakId = '6a4bd364-4b60-4856-a727-efb59d94348e' + $MakKey = 'TB9WQ-WKHVH-W7946-WJTVV-Y6QDD' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + $Esu3Id = '16c08c85-0c8b-4009-9b2b-f1f7319e45f9' + $Esu3Key = '36FB4-RK77J-C867T-QPJBT-4PMW6' + } + 'Microsoft Windows Server 2008 R2 Standard ' { + write-verbose "switch standard edition" + $MakId = '' + $MakKey = 'TB9WQ-WKHVH-W7946-WJTVV-Y6QDD' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + $Esu3Id = '16c08c85-0c8b-4009-9b2b-f1f7319e45f9' + $Esu3Key = '36FB4-RK77J-C867T-QPJBT-4PMW6' + } + 'Microsoft Windows 7 Enterprise ' { + write-verbose "switch Win7 enterprise edition" + $MakId = '9abf5984-9c16-46f2-ad1e-7fe15931a8dd' + $MakKey = 'PRV3H-98HJK-6KKBF-RHYTM-JWCRV' + $Esu1Id = '77db037b-95c3-48d7-a3ab-a9c6d41093e0' + $Esu1Key = 'MJCJ8-24DFX-VGK6H-XYBQ7-F6PR8' + $Esu2Id = '0e00c25d-8795-4fb7-9572-3803d91b6880' + $Esu2Key = 'WX34W-WG8MH-TWWCV-PXK96-RDMTJ' + $Esu3Id = '4220f546-f522-46df-8202-4d07afd26454' + $Esu3Key = 'TF336-89RVD-X2FJJ-YV3KF-Q6KPF' + } + 'Microsoft® Windows Server® 2008 Standard ' { + write-verbose "switch 08 Standard" + $MakId = 'ad2542d4-9154-4c6d-8a44-30f11ee96989' + $MakKey = 'GQK9D-CT4WQ-9KJ87-FKMT8-MR73Q' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + $Esu3Id = '16c08c85-0c8b-4009-9b2b-f1f7319e45f9' + $Esu3Key = '36FB4-RK77J-C867T-QPJBT-4PMW6' + } + 'Microsoft® Windows Server® 2008 Enterprise ' { + write-verbose "switch 08 Enterprise" + $MakId = 'bb1d27c4-959d-4f82-b0fd-c02a7be54732' + $MakKey = 'GQK9D-CT4WQ-9KJ87-FKMT8-MR73Q' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + $Esu3Id = '16c08c85-0c8b-4009-9b2b-f1f7319e45f9' + $Esu3Key = '36FB4-RK77J-C867T-QPJBT-4PMW6' + } +} + +cscript C:\Windows\System32\slmgr.vbs -ipk $MakKey +cscript C:\Windows\System32\slmgr.vbs -ato $MakId +cscript C:\Windows\System32\slmgr.vbs -ipk $Esu1Key +cscript C:\Windows\System32\slmgr.vbs -ato $Esu1Id +cscript C:\Windows\System32\slmgr.vbs -ipk $Esu2Key +cscript C:\Windows\System32\slmgr.vbs -ato $Esu2Id +cscript C:\Windows\System32\slmgr.vbs -ipk $Esu3Key +cscript C:\Windows\System32\slmgr.vbs -ato $Esu3Id \ No newline at end of file diff --git a/SCCM-InstallUpdateViaSoftwareCenter.ps1 b/SCCM-InstallUpdateViaSoftwareCenter.ps1 new file mode 100644 index 0000000..18e8f2f --- /dev/null +++ b/SCCM-InstallUpdateViaSoftwareCenter.ps1 @@ -0,0 +1,4 @@ +If (Get-WmiObject -query 'SELECT * FROM CCM_SoftwareUpdate' -namespace 'ROOT\ccm\ClientSDK' | where-object ArticleId -eq 5001078) { + ([wmiclass]'ROOT\ccm\ClientSDK:CCM_SoftwareUpdatesManager').InstallUpdates([System.Management.ManagementObject[]] (Get-WmiObject -query 'SELECT * FROM CCM_SoftwareUpdate' -namespace 'ROOT\ccm\ClientSDK' | where-object ArticleId -eq 5001078)) +} + diff --git a/SCCM-InstallUpdatesAndTrack.ps1 b/SCCM-InstallUpdatesAndTrack.ps1 new file mode 100644 index 0000000..160b7e9 --- /dev/null +++ b/SCCM-InstallUpdatesAndTrack.ps1 @@ -0,0 +1,18 @@ +$AvailableUpdates = (Get-WmiObject -query 'SELECT * FROM CCM_SoftwareUpdate' -namespace 'ROOT\ccm\ClientSDK') +If($AvailableUpdates){ + ([wmiclass]'ROOT\ccm\ClientSDK:CCM_SoftwareUpdatesManager').InstallUpdates([System.Management.ManagementObject[]] $AvailableUpdates) +} + +([wmiclass]'ROOT\ccm\ClientSDK:CCM_ClientUtilities').DetermineIfRebootPending() + +$InProgress = (Get-WmiObject -query 'SELECT * FROM CCM_SoftwareUpdate' -namespace 'ROOT\ccm\ClientSDK') +$Inprogress.percentcomplete + +#as admin +$UpdateStatus = get-wmiobject -query "SELECT * FROM CCM_UpdateStatus" -namespace "root\ccm\SoftwareUpdates\UpdatesStore" + + +$InstalledUpdates = Get-HotFix | Where-Object InstalledOn -eq (Get-Date).Date +$UpdatesRemaining = Compare-Object $AvailableUpdates.ArticleId $InstalledUpdates.HotFixId.trim("KB") + +$AvailableUpdates | where-object {$_.ArticleId -match $UpdatesRemaining.InputObject} \ No newline at end of file diff --git a/SCCM-New Builds Last 2 Days Query.txt b/SCCM-New Builds Last 2 Days Query.txt new file mode 100644 index 0000000..e8dec15 --- /dev/null +++ b/SCCM-New Builds Last 2 Days Query.txt @@ -0,0 +1,3 @@ +# New Builds Last 2 Days + +select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System inner join SMS_G_System_OPERATING_SYSTEM on SMS_G_System_OPERATING_SYSTEM.ResourceId = SMS_R_System.ResourceId WHERE (DateDiff(day, SMS_G_System_OPERATING_SYSTEM.InstallDate, GetDate()) < 2) \ No newline at end of file diff --git a/SCCM-TSMUninstall.ps1 b/SCCM-TSMUninstall.ps1 new file mode 100644 index 0000000..e95cf2e --- /dev/null +++ b/SCCM-TSMUninstall.ps1 @@ -0,0 +1,84 @@ +#msiexec /uninstall "{19A62C3B-3907-4CC0-B037-DFC883A347B3}" /q +#msiexec /uninstall "{D1607BEA-A9DC-449A-B7A5-770492376485}" /q + +$Service = Get-Service -DisplayName "TSM Client Scheduler" -ErrorAction SilentlyContinue +If ($Service) { + Write-Warning "Stop TSM Client Scheduler service" + Get-Service -DisplayName "TSM Client Scheduler" | Stop-Service + Write-Warning "Remove TSM Client Scheduler service with dsmcutil" + $ServiceRemoval1 = Invoke-Expression -Command '& "C:\Program Files\Tivoli\TSM\baclient\dsmcutil.exe" remove /name:"TSM Client Scheduler"' + $ServiceRemoval2 = Invoke-Expression -Command '& "C:\Program Files\Tivoli\TSM\baclient\dsmcutil.exe" remove /name:"ISP Client Scheduler"' + If ($ServiceRemoval1 -match "The service was successfully removed." -or $ServiceRemoval2 -match "The service was successfully removed.") { + Write-Warning "TSM Client Scheduler service successfully removed" + } + Else { + Write-Error "TSM service removal error" -ErrorAction Stop + } +} +$TSMGuids = @( + "{2068FA80-E4DD-4F9D-AD94-AAF8AAB62142}", + "{F2299C3C-F4D2-4151-AD79-DBAB8DF7DBE6}", + "{89857B75-F612-49B8-83E4-081C4D8D2A2F}", + "{00F61113-3426-49C2-AFAF-E0ECDA4CF352}", + "{C04EDECE-BA6C-4E0D-9959-D30C5485316F}", + "{0EE10C4C-D8EC-48BA-A4B3-C05A5D660395}", + "{19A62C3B-3907-4CC0-B037-DFC883A347B3}", + "{D1F5E133-94F4-4BCE-95DD-656DD4E04B56}", + "{2724D1FA-B655-4EA2-A1AF-C6D2C4630F46}", + "{5A9BA69C-B7E8-49AC-8ACA-A4B1B7A1652F}", + "{66869291-1627-46DF-969C-57B10EBEA7DE}", + "{25A8256B-EB72-4DA5-87CB-0CBB52B8B37B}", + "{5B310A44-6A5B-41DB-964F-49D2292CE5F4}", + "{D1607BEA-A9DC-449A-B7A5-770492376485}", + "{6E2D5C0A-E7AC-4AA2-8C0B-1738E86C0142}" +) +$Service = Get-Service -DisplayName "TSM Client Scheduler" -ErrorAction SilentlyContinue +If ($Service) { + Write-Error "TSM service still exists error" -ErrorAction Stop +} +Else { + Write-Warning "Discover TSM installed apps" + + Write-Warning "Start TSM Removal Loop" + ForEach ($Guid in $TSMGuids) { + Write-Warning "Removing $Guid" + $params = @{ + "FilePath" = "C:\windows\system32\msiexec.exe" + "ArgumentList" = @( + "/uninstall" + "$Guid" + "/q" + ) + "Verb" = "runas" + "PassThru" = $true + } + + $uninstaller = start-process @params + $uninstaller.WaitForExit() + } +} + + +<# + + + $uninstaller = start-process @params + $uninstaller.WaitForExit() + Write-Warning "End TSM JVM Removal" + + Write-Warning "Start TSM Client Removal" + $params = @{ + "FilePath" = "C:\windows\system32\msiexec.exe" + "ArgumentList" = @( + "/uninstall" + "{D1607BEA-A9DC-449A-B7A5-770492376485}" + "/q" + ) + "Verb" = "runas" + "PassThru" = $true + } + + $uninstaller = start-process @params + $uninstaller.WaitForExit() + Write-Warning "End TSM Client Removal" +#> \ No newline at end of file diff --git a/SRMcom/SRM-Cmdlets-master.zip b/SRMcom/SRM-Cmdlets-master.zip new file mode 100644 index 0000000000000000000000000000000000000000..5b0b66d230b5c42e8d620b5c465cc20d768030bd GIT binary patch literal 18819 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 LZ`wF0I1s@bAk@m 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 +Function Get-ProtectionGroup { + [cmdletbinding()] + Param( + [Parameter(position=1)][string] $Name, + [string] $Type, + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan[]] $RecoveryPlan, + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + begin { + $api = Get-ServerApiEndpoint -SrmServer $SrmServer + $pgs = @() + } + process { + if ($RecoveryPlan) { + foreach ($rp in $RecoveryPlan) { + $pgs += $RecoveryPlan.GetInfo().ProtectionGroups + } + $pgs = Select_UniqueByMoRef($pgs) + } else { + $pgs += $api.Protection.ListProtectionGroups() + } + } + end { + $pgs | ForEach-Object { + $pg = $_ + $pgi = $pg.GetInfo() + $selected = (-not $Name -or ($Name -eq $pgi.Name)) -and (-not $Type -or ($Type -eq $pgi.Type)) + if ($selected) { + Add-Member -InputObject $pg -MemberType NoteProperty -Name "Name" -Value $pgi.Name + $pg + } + } + } +} + +<# +.SYNOPSIS +Get the subset of protected VMs matching the input criteria + +.PARAMETER Name +Return protected VMs matching the specified name + +.PARAMETER State +Return protected VMs matching the specified state. For protected +VMs on the protected site this is usually 'ready', for +placeholder VMs this is 'shadowing' + +.PARAMETER ProtectionGroup +Return protected VMs associated with particular protection +groups +#> +Function Get-ProtectedVM { + [cmdletbinding()] + Param( + [Parameter(position=1)][string] $Name, + [VMware.VimAutomation.Srm.Views.SrmProtectionGroupProtectionState] $State, + [VMware.VimAutomation.Srm.Views.SrmProtectionGroupProtectionState] $PeerState, + [switch] $ConfiguredOnly, + [switch] $UnconfiguredOnly, + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroup[]] $ProtectionGroup, + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan[]] $RecoveryPlan, + [string] $ProtectionGroupName, + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + if ($null -eq $ProtectionGroup) { + $ProtectionGroup = Get-ProtectionGroup -Name $ProtectionGroupName -RecoveryPlan $RecoveryPlan -SrmServer $SrmServer + } + $ProtectionGroup | ForEach-Object { + $pg = $_ + $pg.ListProtectedVms() | ForEach-Object { + # try and update the view data for the protected VM + try { + $_.Vm.UpdateViewData() + } catch { + Write-Error $_ + } finally { + $_ + } + } | Where-object { -not $Name -or ($Name -eq $_.Vm.Name) } | + where-object { -not $State -or ($State -eq $_.State) } | + where-object { -not $PeerState -or ($PeerState -eq $_.PeerState) } | + where-object { ($ConfiguredOnly -and $_.NeedsConfiguration -eq $false) -or ($UnconfiguredOnly -and $_.NeedsConfiguration -eq $true) -or (-not $ConfiguredOnly -and -not $UnconfiguredOnly) } + } +} + + +<# +.SYNOPSIS +Get the unprotected VMs that are associated with a protection group + +.PARAMETER ProtectionGroup +Return unprotected VMs associated with particular protection +groups. For VR protection groups this is VMs that are associated +with the PG but not configured, For ABR protection groups this is +VMs on replicated datastores associated with the group that are not +configured. +#> +Function Get-UnProtectedVM { + [cmdletbinding()] + Param( + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroup[]] $ProtectionGroup, + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan[]] $RecoveryPlan, + [string] $ProtectionGroupName, + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + if ($null -eq $ProtectionGroup) { + $ProtectionGroup = Get-ProtectionGroup -Name $ProtectionGroupName -RecoveryPlan $RecoveryPlan -SrmServer $SrmServer + } + + $associatedVMs = @() + $protectedVmRefs = @() + + $ProtectionGroup | ForEach-Object { + $pg = $_ + # For VR listAssociatedVms to get list of VMs + if ($pg.GetInfo().Type -eq 'vr') { + $associatedVMs += @($pg.ListAssociatedVms() | Get-VIObjectByVIView) + } + # TODO test this: For ABR get VMs on GetProtectedDatastore + if ($pg.GetInfo().Type -eq 'san') { + $pds = @(Get-ProtectedDatastore -ProtectionGroup $pg) + $pds | ForEach-Object { + $ds = Get-Datastore -id $_.MoRef + $associatedVMs += @(Get-VM -Datastore $ds) + } + } + + # get protected VMs + $protectedVmRefs += @(Get-ProtectedVM -ProtectionGroup $pg | ForEach-Object { $_.Vm.MoRef } | Select-Object -Unique) + } + + # get associated but unprotected VMs + $associatedVMs | Where-Object { $protectedVmRefs -notcontains $_.ExtensionData.MoRef } +} + + +#Untested as I don't have ABR setup in my lab yet +<# +.SYNOPSIS +Get the subset of protected Datastores matching the input criteria + +.PARAMETER ProtectionGroup +Return protected datastores associated with particular protection +groups +#> +Function Get-ProtectedDatastore { + [cmdletbinding()] + Param( + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroup[]] $ProtectionGroup, + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan[]] $RecoveryPlan, + [string] $ProtectionGroupName, + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + if (-not $ProtectionGroup) { + $ProtectionGroup = Get-ProtectionGroup -Name $ProtectionGroupName -RecoveryPlan $RecoveryPlan -SrmServer $SrmServer + } + $ProtectionGroup | ForEach-Object { + $pg = $_ + if ($pg.GetInfo().Type -eq 'san') { # only supported for array based replication datastores + $pg.ListProtectedDatastores() + } + } +} + + +#Untested as I don't have ABR setup in my lab yet +<# +.SYNOPSIS +Get the replicated datastores that aren't associated with a protection group. +#> +Function Get-ReplicatedDatastore { + [cmdletbinding()] + Param( + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + $api = Get-ServerApiEndpoint -SrmServer $SrmServer + + $api.Protection.ListUnassignedReplicatedDatastores() +} + +<# +.SYNOPSIS +Protect a VM using SRM + +.PARAMETER ProtectionGroup +The protection group that this VM will belong to + +.PARAMETER Vm +The virtual machine to protect +#> +Function Protect-VM { + [cmdletbinding()] + Param( + [Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroup] $ProtectionGroup, + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $Vm, + [Parameter (ValueFromPipeline=$true)][VMware.Vim.VirtualMachine] $VmView + ) + + $moRef = Get_MoRefFromVmObj -Vm $Vm -VmView $VmView + + $pgi = $ProtectionGroup.GetInfo() + #TODO query protection status first + + if ($moRef) { + if ($pgi.Type -eq 'vr') { + $ProtectionGroup.AssociateVms(@($moRef)) + } + $protectionSpec = New-Object VMware.VimAutomation.Srm.Views.SrmProtectionGroupVmProtectionSpec + $protectionSpec.Vm = $moRef + $protectTask = $ProtectionGroup.ProtectVms($protectionSpec) + while(-not $protectTask.IsComplete()) { Start-Sleep -Seconds 1 } + $protectTask.GetResult() + } else { + throw "Can't protect the VM, no MoRef found." + } +} + + +<# +.SYNOPSIS +Unprotect a VM using SRM + +.PARAMETER ProtectionGroup +The protection group that this VM will be removed from + +.PARAMETER Vm +The virtual machine to unprotect +#> +Function Unprotect-VM { + [cmdletbinding()] + Param( + [Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroup] $ProtectionGroup, + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $Vm, + [Parameter (ValueFromPipeline=$true)][VMware.Vim.VirtualMachine] $VmView, + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroupProtectedVm] $ProtectedVm + ) + + $moRef = Get_MoRefFromVmObj -Vm $Vm -VmView $VmView -ProtectedVm $ProtectedVm + + $pgi = $ProtectionGroup.GetInfo() + $protectTask = $ProtectionGroup.UnprotectVms($moRef) + while(-not $protectTask.IsComplete()) { Start-Sleep -Seconds 1 } + if ($pgi.Type -eq 'vr') { + $ProtectionGroup.UnassociateVms(@($moRef)) + } + $protectTask.GetResult() +} + +<# +.SYNOPSIS +Get a protection group folder + +.PARAMETER SrmServer +The SRM Server to query for the protection group folder +#> +Function Get-ProtectionGroupFolder { + [cmdletbinding()] + Param( + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + $api = Get-ServerApiEndpoint -SrmServer $SrmServer + + $folder = $api.Protection.GetProtectionGroupRootFolder() + + return $folder +} + +<# +.SYNOPSIS +Create a new protection group + +.PARAMETER Name +The name of the protection group + +.PARAMETER Description +Description of the protection group + +.PARAMETER Folder +The protection group folder in which to create the new protection group + +.PARAMETER ArrayReplication +Set if protection group is for replicating VMs using Array based replication + +.PARAMETER vSphereReplication +Set if protection group is for replicating VMs with vSphere Replication + +.PARAMETER VMs +For vSphere Replication based protection, the VMs to add to the replication +group. These should already be replicated. + +.PARAMETER VMViews +For vSphere Replication based protection, the VMs to add to the replication +group. These should already be replicated. + +.PARAMETER SrmServer +The SRM Server to perform the operation against +#> +Function New-ProtectionGroup { + [cmdletbinding(DefaultParameterSetName="VR", SupportsShouldProcess=$True, ConfirmImpact="Medium")] + [OutputType([VMware.VimAutomation.Srm.Views.SrmProtectionGroup])] + Param( + [Parameter (Mandatory=$true)] $Name, + $Description, + [VMware.VimAutomation.Srm.Views.SrmProtectionGroupFolder] $Folder, + [Parameter (ParameterSetName="ABR", Mandatory=$true)][switch] $ArrayReplication, + [Parameter (ValueFromPipeline=$true, ParameterSetName="ABR")][VMware.VimAutomation.ViCore.Types.V1.DatastoreManagement.Datastore[]] $Datastores, + [Parameter (ValueFromPipeline=$true, ParameterSetName="ABR")][VMware.Vim.Datastore[]] $DatastoreViews, + [Parameter (ParameterSetName="VR", Mandatory=$true)][switch] $vSphereReplication, + [Parameter (ValueFromPipeline=$true, ParameterSetName="VR")][VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]] $VMs, + [Parameter (ValueFromPipeline=$true, ParameterSetName="VR")][VMware.Vim.VirtualMachine[]] $VMViews, + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + $api = Get-ServerApiEndpoint $SrmServer + [VMware.VimAutomation.Srm.Views.SrmCreateProtectionGroupTask] $task = $null + + #get root folder if this wasn't specified as a parameter + if(-not $Folder) { + $Folder = Get-ProtectionGroupFolder -SrmServer $SrmServer + } + + if ($vSphereReplication) { + #create list of managed object references from VM and/or VM view arrays + [VMware.Vim.ManagedObjectReference[]]$moRefs = @() + foreach ($vm in $VMs) { + $moRefs += Get_MoRefFromVmObj -Vm $Vm + } + foreach ($VmView in $VMViews) { + $moRefs += Get_MoRefFromVmObj -VmView $VmView + } + + if ($pscmdlet.ShouldProcess($Name, "New")) { + $task = $api.Protection.CreateHbrProtectionGroup($Folder.MoRef, $Name, $Description, $moRefs) + } + + } elseif ($ArrayReplication) { + #create list of managed object references from VM and/or VM view arrays + $moRefs = @() + foreach ($ds in $Datastores) { + $moRefs += $ds.ExtensionData.MoRef + } + foreach ($DsView in $DatastoreViews) { + $moRefs += $DsView.MoRef + } + + if ($pscmdlet.ShouldProcess($Name, "New")) { + $task = $api.Protection.CreateAbrProtectionGroup($Folder.MoRef, $Name, $Description, $moRefs) + } + + } else { + throw "Undetermined protection group type" + } + + # Complete task + while(-not $task.IsCreateProtectionGroupComplete()) { Start-Sleep -Seconds 1 } + + # Retrieve the protection group, and protect associated VMs + $pg = $task.GetNewProtectionGroup() + if ($pg) { + $unProtectedVMs = Get-UnProtectedVM -ProtectionGroup $pg + $unProtectedVMs | Protect-VM -ProtectionGroup $pg + } + + return $pg +} + + +<# +.SYNOPSIS +Delete a protection group + +.PARAMETER ProtectionGroup +The protection group to remove + +.PARAMETER SrmServer +The SRM Server to perform the operation against +#> +Function Remove-ProtectionGroup { + [cmdletbinding(SupportsShouldProcess=$True, ConfirmImpact="High")] + [OutputType([VMware.VimAutomation.Srm.Views.RemoveProtectionGroupTask])] + Param( + [Parameter (Mandatory=$true, ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroup] $ProtectionGroup, + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + $api = Get-ServerApiEndpoint $SrmServer + [VMware.VimAutomation.Srm.Views.RemoveProtectionGroupTask] $task = $null + + $pginfo = $ProtectionGroup.GetInfo() + if ($pscmdlet.ShouldProcess($pginfo.Name, "Remove")) { + $task = $api.Protection.RemoveProtectionGroup($ProtectionGroup.MoRef) + } + + return $task +} diff --git a/SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/Meadowcroft.Srm.Recovery.ps1 b/SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/Meadowcroft.Srm.Recovery.ps1 new file mode 100644 index 0000000..1b2eaca --- /dev/null +++ b/SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/Meadowcroft.Srm.Recovery.ps1 @@ -0,0 +1,556 @@ +# SRM Helper Methods - https://github.com/benmeadowcroft/SRM-Cmdlets + +<# +.SYNOPSIS +Get the subset of recovery plans matching the input criteria + +.PARAMETER Name +Return recovery plans matching the specified name + +.PARAMETER ProtectionGroup +Return recovery plans associated with particular protection +groups +#> +Function Get-RecoveryPlan { + [cmdletbinding()] + Param( + [Parameter(position=1)][string] $Name, + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroup[]] $ProtectionGroup, + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + begin { + $api = Get-ServerApiEndpoint -SrmServer $SrmServer + $rps = @() + } + process { + if ($ProtectionGroup) { + foreach ($pg in $ProtectionGroup) { + $rps += $pg.ListRecoveryPlans() + } + $rps = Select_UniqueByMoRef($rps) + } else { + $rps += $api.Recovery.ListPlans() + } + } + end { + $rps | ForEach-Object { + $rp = $_ + $rpi = $rp.GetInfo() + $selected = (-not $Name -or ($Name -eq $rpi.Name)) + if ($selected) { + Add-Member -InputObject $rp -MemberType NoteProperty -Name "Name" -Value $rpi.Name + $rp + } + } + } +} + +<# +.SYNOPSIS +Start a Recovery Plan action like test, recovery, cleanup, etc. + +.PARAMETER RecoveryPlan +The recovery plan to start + +.PARAMETER RecoveryMode +The recovery mode to invoke on the plan. May be one of "Test", "Cleanup", "Failover", "Migrate", "Reprotect" +#> +Function Start-RecoveryPlan { + [cmdletbinding(SupportsShouldProcess=$True, ConfirmImpact="High")] + Param( + [Parameter (Mandatory=$true, ValueFromPipeline=$true, Position=1)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan] $RecoveryPlan, + [VMware.VimAutomation.Srm.Views.SrmRecoveryPlanRecoveryMode] $RecoveryMode = [VMware.VimAutomation.Srm.Views.SrmRecoveryPlanRecoveryMode]::Test, + [bool] $SyncData = $True + ) + + # Validate with informative error messages + $rpinfo = $RecoveryPlan.GetInfo() + + # Create recovery options + $rpOpt = New-Object VMware.VimAutomation.Srm.Views.SrmRecoveryOptions + $rpOpt.SyncData = $SyncData + + # Prompt the user to confirm they want to execute the action + if ($pscmdlet.ShouldProcess($rpinfo.Name, $RecoveryMode)) { + if ($rpinfo.State -eq 'Protecting') { + throw "This recovery plan action needs to be initiated from the other SRM instance" + } + + $RecoveryPlan.Start($RecoveryMode, $rpOpt) + } +} + +<# +.SYNOPSIS +Stop a running Recovery Plan action. + +.PARAMETER RecoveryPlan +The recovery plan to stop +#> +Function Stop-RecoveryPlan { + [cmdletbinding(SupportsShouldProcess=$True,ConfirmImpact="High")] + Param( + [Parameter (Mandatory=$true, ValueFromPipeline=$true, Position=1)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan] $RecoveryPlan + ) + + # Validate with informative error messages + $rpinfo = $RecoveryPlan.GetInfo() + + # Prompt the user to confirm they want to cancel the running action + if ($pscmdlet.ShouldProcess($rpinfo.Name, 'Cancel')) { + + $RecoveryPlan.Cancel() + } +} + +<# +.SYNOPSIS +Retrieve the historical results of a recovery plan + +.PARAMETER RecoveryPlan +The recovery plan to retrieve the history for +#> +Function Get-RecoveryPlanResult { + [cmdletbinding()] + Param( + [Parameter (Mandatory=$true, ValueFromPipeline=$true, Position=1)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan] $RecoveryPlan, + [VMware.VimAutomation.Srm.Views.SrmRecoveryPlanRecoveryMode] $RecoveryMode, + [VMware.VimAutomation.Srm.Views.SrmRecoveryResultResultState] $ResultState, + [DateTime] $StartedAfter, + [DateTime] $startedBefore, + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + $api = Get-ServerApiEndpoint -SrmServer $SrmServer + + # Get the history objects + $history = $api.Recovery.GetHistory($RecoveryPlan.MoRef) + $resultCount = $history.GetResultCount() + + if ($resultCount -gt 0) { + $results = $history.GetRecoveryResult($resultCount) + + $results | + Where-Object { -not $RecoveryMode -or $_.RunMode -eq $RecoveryMode } | + Where-Object { -not $ResultState -or $_.ResultState -eq $ResultState } | + Where-Object { $null -eq $StartedAfter -or $_.StartTime -gt $StartedAfter } | + Where-Object { $null -eq $StartedBefore -or $_.StartTime -lt $StartedBefore } + } +} + +<# +.SYNOPSIS +Exports a recovery plan result object to XML format + +.PARAMETER RecoveryPlanResult +The recovery plan result to export +#> +Function Export-RecoveryPlanResultAsXml { + [cmdletbinding()] + [OutputType([xml])] + Param( + [Parameter (Mandatory=$true, ValueFromPipeline=$true, Position=1)][VMware.VimAutomation.Srm.Views.SrmRecoveryResult] $RecoveryPlanResult, + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + $api = Get-ServerApiEndpoint -SrmServer $SrmServer + + $RecoveryPlan = $RecoveryPlanResult.Plan + $history = $api.Recovery.GetHistory($RecoveryPlan.MoRef) + $lines = $history.GetResultLength($RecoveryPlanResult.Key) + [xml] $history.RetrieveStatus($RecoveryPlanResult.Key, 0, $lines) +} + +<# +.SYNOPSIS +Add a protection group to a recovery plan. This requires SRM 5.8 or later. + +.PARAMETER RecoveryPlan +The recovery plan the protection group will be associated with + +.PARAMETER ProtectionGroup +The protection group to associate with the recovery plan +#> +Function Add-ProtectionGroupToRecoveryPlan { + [cmdletbinding()] + Param( + [Parameter (Mandatory=$true, Position=1)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan] $RecoveryPlan, + [Parameter (Mandatory=$true, ValueFromPipeline=$true, Position=2)][VMware.VimAutomation.Srm.Views.SrmProtectionGroup] $ProtectionGroup + ) + + if ($RecoveryPlan -and $ProtectionGroup) { + foreach ($pg in $ProtectionGroup) { + try { + $RecoveryPlan.AddProtectionGroup($pg.MoRef) + } catch { + Write-Error $_ + } + } + } +} + +<# +.SYNOPSIS +Remove a protection group to a recovery plan. This requires SRM 6.5 or later. + +.PARAMETER RecoveryPlan +The recovery plan the protection group will be disassociated from + +.PARAMETER ProtectionGroup +The protection group to disassociate from the recovery plan +#> +Function Remove-ProtectionGroupFromRecoveryPlan { + [cmdletbinding()] + Param( + [Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan] $RecoveryPlan, + [Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroup] $ProtectionGroup + ) + + if ($RecoveryPlan -and $ProtectionGroup) { + foreach ($pg in $ProtectionGroup) { + try { + $RecoveryPlan.RemoveProtectionGroupFromRecoveryPlan($pg.MoRef) + } catch { + Write-Error $_ + } + } + } +} + +<# +.SYNOPSIS +Get the recovery settings of a protected VM. This requires SRM 5.8 or later. + +.PARAMETER RecoveryPlan +The recovery plan the settings will be retrieved from. + +.PARAMETER Vm +The virtual machine to retieve recovery settings for. + +#> +Function Get-RecoverySetting { + [cmdletbinding()] + Param( + [Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan] $RecoveryPlan, + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $Vm, + [Parameter (ValueFromPipeline=$true)][VMware.Vim.VirtualMachine] $VmView, + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroupProtectedVm] $ProtectedVm + ) + + $moRef = Get_MoRefFromVmObj -Vm $Vm -VmView $VmView -ProtectedVm $ProtectedVm + + if ($RecoveryPlan -and $moRef) { + $RecoveryPlan.GetRecoverySettings($moRef) + } +} + +<# +.SYNOPSIS +Get the recovery settings of a protected VM. This requires SRM 5.8 or later. + +.PARAMETER RecoveryPlan +The recovery plan the settings will be retrieved from. + +.PARAMETER Vm +The virtual machine to configure recovery settings on. + +.PARAMETER RecoverySettings +The recovery settings to configure. These should have been retrieved via a +call to Get-RecoverySettings + +#> +Function Set-RecoverySetting { + [cmdletbinding(SupportsShouldProcess=$true, ConfirmImpact="Medium")] + Param( + [Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan] $RecoveryPlan, + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $Vm, + [Parameter (ValueFromPipeline=$true)][VMware.Vim.VirtualMachine] $VmView, + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroupProtectedVm] $ProtectedVm, + [Parameter (Mandatory=$true, ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoverySettings] $RecoverySettings + ) + + + $moRef = Get_MoRefFromVmObj -Vm $Vm -VmView $VmView -ProtectedVm $ProtectedVm + + if ($RecoveryPlan -and $moRef -and $RecoverySettings) { + if ($PSCmdlet.ShouldProcess("$moRef", "Set")) { + $RecoveryPlan.SetRecoverySettings($moRef, $RecoverySettings) + } + } +} + +<# +.SYNOPSIS +Create a new per-Vm command to add to the SRM Recovery Plan + +.PARAMETER Command +The command script to execute. + +.PARAMETER Description +The user friendly description of this script. + +.PARAMETER Timeout +The number of seconds this command has to execute before it will be timedout. + +.PARAMETER RunInRecoveredVm +For a post-power on command this flag determines whether it will run on the +recovered VM or on the SRM server. + +#> +Function New-Command { + [cmdletbinding(SupportsShouldProcess=$true, ConfirmImpact="None")] + Param( + [Parameter (Mandatory=$true)][string] $Command, + [Parameter (Mandatory=$true)][string] $Description, + [int] $Timeout = 300, + [switch] $RunInRecoveredVm = $false + ) + + if($PSCmdlet.ShouldProcess("Description", "New")) { + $srmWsdlCmd = New-Object VMware.VimAutomation.Srm.WsdlTypes.SrmCommand + $srmCmd = New-Object VMware.VimAutomation.Srm.Views.SrmCommand -ArgumentList $srmWsdlCmd + $srmCmd.Command = $Command + $srmCmd.Description = $Description + $srmCmd.RunInRecoveredVm = $RunInRecoveredVm + $srmCmd.Timeout = $Timeout + $srmCmd.Uuid = [guid]::NewGuid() + + return $srmCmd + } +} + +<# Internal function #> +Function Add_Command { + [cmdletbinding()] + Param( + [Parameter (Mandatory=$true, ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoverySettings] $RecoverySettings, + [Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmCommand] $SrmCommand, + [Parameter (Mandatory=$true)][bool] $PostRecovery + ) + + if ($PostRecovery) { + $commands = $RecoverySettings.PostPowerOnCallouts + } else { + $commands = $RecoverySettings.PrePowerOnCallouts + } + + if (-not $commands) { + $commands = New-Object System.Collections.Generic.List[VMware.VimAutomation.Srm.Views.SrmCallout] + } + $commands.Add($SrmCommand) + + if ($PostRecovery) { + $RecoverySettings.PostPowerOnCallouts = $commands + } else { + $RecoverySettings.PrePowerOnCallouts = $commands + } +} + +<# +.SYNOPSIS +Add an SRM command to the set of pre recovery callouts for a VM. + +.PARAMETER RecoverySettings +The recovery settings to update. These should have been retrieved via a +call to Get-RecoverySettings + +.PARAMETER SrmCommand +The command to add to the list. + +#> +Function Add-PreRecoveryCommand { + [cmdletbinding()] + [OutputType([VMware.VimAutomation.Srm.Views.SrmRecoverySettings])] + Param( + [Parameter (Mandatory=$true, ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoverySettings] $RecoverySettings, + [Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmCommand] $SrmCommand + ) + Add_Command -RecoverySettings $RecoverySettings -SrmCommand $SrmCommand -PostRecovery $false + return $RecoverySettings +} + +<# +.SYNOPSIS +Remove an SRM command from the set of pre recovery callouts for a VM. + +.PARAMETER RecoverySettings +The recovery settings to update. These should have been retrieved via a +call to Get-RecoverySettings + +.PARAMETER SrmCommand +The command to remove from the list. + +#> +Function Remove-PreRecoveryCommand { + [cmdletbinding(SupportsShouldProcess=$true, ConfirmImpact="Low")] + [OutputType([VMware.VimAutomation.Srm.Views.SrmRecoverySettings])] + Param( + [Parameter (Mandatory=$true, ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoverySettings] $RecoverySettings, + [Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmCommand] $SrmCommand + ) + + if ($pscmdlet.ShouldProcess($SrmCommand.Description, "Remove")) { + $RecoverySettings.PrePowerOnCallouts.Remove($SrmCommand) + } + + return $RecoverySettings +} + +<# +.SYNOPSIS +Add an SRM command to the set of post recovery callouts for a VM. + +.PARAMETER RecoverySettings +The recovery settings to update. These should have been retrieved via a +call to Get-RecoverySettings + +.PARAMETER SrmCommand +The command to add to the list. + +#> +Function Add-PostRecoveryCommand { + [cmdletbinding()] + [OutputType([VMware.VimAutomation.Srm.Views.SrmRecoverySettings])] + Param( + [Parameter (Mandatory=$true, ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoverySettings] $RecoverySettings, + [Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmCommand] $SrmCommand + ) + + Add_Command -RecoverySettings $RecoverySettings -SrmCommand $SrmCommand -PostRecovery $true + + return $RecoverySettings +} + + +<# +.SYNOPSIS +Remove an SRM command from the set of post recovery callouts for a VM. + +.PARAMETER RecoverySettings +The recovery settings to update. These should have been retrieved via a +call to Get-RecoverySettings + +.PARAMETER SrmCommand +The command to remove from the list. + +#> +Function Remove-PostRecoveryCommand { + [cmdletbinding(SupportsShouldProcess=$true, ConfirmImpact="Low")] + [OutputType([VMware.VimAutomation.Srm.Views.SrmRecoverySettings])] + Param( + [Parameter (Mandatory=$true, ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmRecoverySettings] $RecoverySettings, + [Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmCommand] $SrmCommand + ) + + if ($pscmdlet.ShouldProcess($SrmCommand.Description, "Remove")) { + $RecoverySettings.PostPowerOnCallouts.Remove($SrmCommand) + } + + return $RecoverySettings +} + + +<# +.SYNOPSIS +Create a new recovery plan + +.PARAMETER Name +The name for this recovery plan + +.PARAMETER Description +A description of the recovery plan + +.PARAMETER Folder +The recovery plan folder in which to create this recovery plan. Will default to +the root recovery plan folder + +.PARAMETER ProtectionGroups +The protection groups to associate with this recovery plan + +.PARAMETER TestNetworkMappings +The test network mappings to configure as part of this recovery plan + +.PARAMETER SrmServer +The SRM Server to operate against +#> +Function New-RecoveryPlan { + [cmdletbinding(SupportsShouldProcess=$true, ConfirmImpact="Medium")] + Param( + [Parameter (Mandatory=$true)][string] $Name, + [string] $Description, + [VMware.VimAutomation.Srm.Views.SrmRecoveryPlanFolder] $Folder, + [VMware.VimAutomation.Srm.Views.SrmProtectionGroup[]] $ProtectionGroups, + [VMware.VimAutomation.Srm.Views.SrmRecoveryTestNetworkMapping[]] $TestNetworkMappings, + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + $api = Get-ServerApiEndpoint -SrmServer $SrmServer + + if (-not $Folder) { + $Folder = Get-RecoveryPlanFolder -SrmServer $SrmServer + } + + $protectionGroupmRefs += @( $ProtectionGroups | ForEach-Object { $_.MoRef } | Select-Object -Unique) + + [VMware.VimAutomation.Srm.Views.CreateRecoveryPlanTask] $task = $null + + if ($PSCmdlet.ShouldProcess($Name, "New")) { + $task = $api.Recovery.CreateRecoveryPlan( + $Name, + $Folder.MoRef, + $protectionGroupmRefs, + $Description, + $TestNetworkMappings + ) + } + + while(-not $task.IsCreateRecoveryPlanComplete()) { Start-Sleep -Seconds 1 } + + $task.GetNewRecoveryPlan() +} + +<# +.SYNOPSIS +Remove a recovery plan permanently + +.PARAMETER RecoveryPlan +The recovery plan to remove + +.PARAMETER SrmServer +The SRM Server to operate against +#> +Function Remove-RecoveryPlan { + [cmdletbinding(SupportsShouldProcess=$True, ConfirmImpact="High")] + Param( + [Parameter (Mandatory=$true)][VMware.VimAutomation.Srm.Views.SrmRecoveryPlan] $RecoveryPlan, + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + $api = Get-ServerApiEndpoint -SrmServer $SrmServer + + $rpinfo = $RecoveryPlan.GetInfo() + if ($pscmdlet.ShouldProcess($rpinfo.Name, "Remove")) { + $api.Recovery.DeleteRecoveryPlan($RecoveryPlan.MoRef) + } +} + +<# +.SYNOPSIS +Get a recovery plan folder + +.PARAMETER SrmServer +The SRM Server to query for the recovery plan folder +#> +Function Get-RecoveryPlanFolder { + [cmdletbinding()] + Param( + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + $api = Get-ServerApiEndpoint -SrmServer $SrmServer + + $folder = $api.Recovery.GetRecoveryPlanRootFolder() + + return $folder +} diff --git a/SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/Meadowcroft.Srm.Storage.ps1 b/SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/Meadowcroft.Srm.Storage.ps1 new file mode 100644 index 0000000..8880f36 --- /dev/null +++ b/SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/Meadowcroft.Srm.Storage.ps1 @@ -0,0 +1,24 @@ +# SRM Helper Methods - https://github.com/benmeadowcroft/SRM-Cmdlets + +<# +.SYNOPSIS +Trigger Discover Devices for Site Recovery Manager + +.OUTPUTS +Returns discover devices task +#> +Function Start-DiscoverDevice { + [cmdletbinding(SupportsShouldProcess=$True, ConfirmImpact="Medium")] + [OutputType([VMware.VimAutomation.Srm.Views.DiscoverDevicesTask])] + Param( + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + $api = Get-ServerApiEndpoint -SrmServer $SrmServer + $name = $SrmServer.Name + [VMware.VimAutomation.Srm.Views.DiscoverDevicesTask] $task = $null + if ($pscmdlet.ShouldProcess($name, "Rescan Storage Devices")) { + $task = $api.Storage.DiscoverDevices() + } + return $task +} diff --git a/SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/Meadowcroft.Srm.psd1 b/SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/Meadowcroft.Srm.psd1 new file mode 100644 index 0000000..996a493 --- /dev/null +++ b/SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/Meadowcroft.Srm.psd1 @@ -0,0 +1,92 @@ +# +# Module manifest for module 'Meadowcroft.Srm' +# + +@{ + +# Script module or binary module file associated with this manifest. +RootModule = 'Meadowcroft.Srm.psm1' + +# Version number of this module. +ModuleVersion = '0.2' + +# ID used to uniquely identify this module +GUID = 'f9247009-9168-4a21-831b-819f82884ffe' + +# Author of this module +Author = 'Ben Meadowcroft' + +# Company or vendor of this module +CompanyName = 'VMware, Inc' + +# Copyright statement for this module +Copyright = '(c) 2014 - 2017. All rights reserved.' + +# Description of the functionality provided by this module +# Description = '' + +# Minimum version of the Windows PowerShell engine required by this module +# PowerShellVersion = '' + +# Name of the Windows PowerShell host required by this module +# PowerShellHostName = '' + +# Minimum version of the Windows PowerShell host required by this module +# PowerShellHostVersion = '' + +# Minimum version of Microsoft .NET Framework required by this module +# DotNetFrameworkVersion = '' + +# Minimum version of the common language runtime (CLR) required by this module +# CLRVersion = '' + +# Processor architecture (None, X86, Amd64) required by this module +# ProcessorArchitecture = '' + +# Modules that must be imported into the global environment prior to importing this module +RequiredModules = @{ModuleName='VMware.VimAutomation.Srm'; ModuleVersion='6.5'} + +# Assemblies that must be loaded prior to importing this module +# RequiredAssemblies = @() + +# Script files (.ps1) that are run in the caller's environment prior to importing this module. +# ScriptsToProcess = @() + +# Type files (.ps1xml) to be loaded when importing this module +# TypesToProcess = @() + +# Format files (.ps1xml) to be loaded when importing this module +# FormatsToProcess = @() + +# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess +NestedModules = 'Meadowcroft.Srm.Recovery.ps1','Meadowcroft.Srm.Protection.ps1','Meadowcroft.Srm.Storage.ps1' +# NestedModules = @() + +# Functions to export from this module, note that internal functions use '_' not '-' as separator +FunctionsToExport = '*-*' + +# Cmdlets to export from this module +CmdletsToExport = '*' + +# Variables to export from this module +VariablesToExport = '*' + +# Aliases to export from this module +AliasesToExport = '*' + +# List of all modules packaged with this module +# ModuleList = @() + +# List of all files packaged with this module +# FileList = @() + +# Private data to pass to the module specified in RootModule/ModuleToProcess +# PrivateData = '' + +# HelpInfo URI of this module +# HelpInfoURI = '' + +# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. +DefaultCommandPrefix = 'Srm' + +} diff --git a/SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/Meadowcroft.Srm.psm1 b/SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/Meadowcroft.Srm.psm1 new file mode 100644 index 0000000..ed7c042 --- /dev/null +++ b/SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/Meadowcroft.Srm.psm1 @@ -0,0 +1,148 @@ +# SRM Helper Methods - https://github.com/benmeadowcroft/SRM-Cmdlets + +<# +.SYNOPSIS +This is intended to be an "internal" function only. It filters a +pipelined input of objects and elimiates duplicates as identified +by the MoRef property on the object. + +.LINK +https://github.com/benmeadowcroft/SRM-Cmdlets/ +#> +Function Select_UniqueByMoRef { + + Param( + [Parameter (ValueFromPipeline=$true)] $in + ) + process { + $moref = New-Object System.Collections.ArrayList + $in | Sort-Object | Select-Object MoRef -Unique | ForEach-Object { $moref.Add($_.MoRef) } > $null + $in | ForEach-Object { + if ($_.MoRef -in $moref) { + $moref.Remove($_.MoRef) + $_ #output + } + } + } +} + +<# +.SYNOPSIS +This is intended to be an "internal" function only. It gets the +MoRef property of a VM from either a VM object, a VM view, or the +protected VM object. +#> +Function Get_MoRefFromVmObj { + Param( + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $Vm, + [Parameter (ValueFromPipeline=$true)][VMware.Vim.VirtualMachine] $VmView, + [Parameter (ValueFromPipeline=$true)][VMware.VimAutomation.Srm.Views.SrmProtectionGroupProtectedVm] $ProtectedVm + ) + + + $moRef = $null + if ($Vm.ExtensionData.MoRef) { # VM object + $moRef = $Vm.ExtensionData.MoRef + } elseif ($VmView.MoRef) { # VM view + $moRef = $VmView.MoRef + } elseif ($protectedVm) { + $moRef = $ProtectedVm.Vm.MoRef + } + + $moRef +} + +<# +.SYNOPSIS +Lookup the srm instance for a specific server. +#> +Function Get-Server { + [cmdletbinding()] + Param( + [string] $SrmServerAddress, + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + $found = $null + + if ($SrmServer) { + $found = $SrmServer + } elseif ($SrmServerAddress) { + # search for server address in default servers + $global:DefaultSrmServers | ForEach-Object { + if ($_.Name -ieq $SrmServerAddress) { + $found = $_ + } + } + if (-not $found) { + throw "SRM server $SrmServerAddress not found. Connect-Server must be called first." + } + } + + if (-not $found) { + #default result + $found = $global:DefaultSrmServers[0] + } + + return $found; +} + +<# +.SYNOPSIS +Retrieve the SRM Server Version +#> +Function Get-ServerVersion { + [cmdletbinding()] + Param( + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + $srm = Get-Server $SrmServer + $srm.Version +} + +<# +.SYNOPSIS +Lookup the SRM API endpoint for a specific server. +#> +Function Get-ServerApiEndpoint { + [cmdletbinding()] + Param( + [string] $SrmServerAddress, + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $SrmServer + ) + + [VMware.VimAutomation.Srm.Types.V1.SrmServer] $server = Get-Server -SrmServerAddress $SrmServerAddress -SrmServer $SrmServer + + return $server.ExtensionData +} + +<# +.SYNOPSIS +Get the placeholder VMs that are associated with SRM +#> +Function Get-PlaceholderVM { + [cmdletbinding()] + Param() + Get-VM @Args | Where-Object {$_.ExtensionData.Config.ManagedBy.extensionKey -like "com.vmware.vcDr*" -and $_.ExtensionData.Config.ManagedBy.Type -ieq 'placeholderVm'} +} + +<# +.SYNOPSIS +Get the test VMs that are associated with SRM +#> +Function Get-TestVM { + [cmdletbinding()] + Param() + Get-VM @Args | Where-Object {$_.ExtensionData.Config.ManagedBy.extensionKey -like "com.vmware.vcDr*" -and $_.ExtensionData.Config.ManagedBy.Type -ieq 'testVm'} +} + +<# +.SYNOPSIS +Get the VMs that are replicated using vSphere Replication. These may not be SRM +protected VMs. +#> +Function Get-ReplicatedVM { + [cmdletbinding()] + Param() + Get-VM @Args | Where-Object {($_.ExtensionData.Config.ExtraConfig | Where-Object { $_.Key -eq 'hbr_filter.destination' -and $_.Value } )} +} diff --git a/SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/NOTICE.txt b/SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/NOTICE.txt new file mode 100644 index 0000000..2eb2d48 --- /dev/null +++ b/SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/NOTICE.txt @@ -0,0 +1,7 @@ + +Copyright (c) 2017 VMware, Inc. All Rights Reserved. + +This product is licensed to you under the Apache License version 2.0 (the "License"). You may not use this product except in compliance with the License. + +This product may include a number of subcomponents with separate copyright notices and license terms. Your use of these subcomponents is subject to the terms and conditions of the subcomponent's license, as noted in the LICENSE file. + diff --git a/SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/README.md b/SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/README.md new file mode 100644 index 0000000..00d775e --- /dev/null +++ b/SRMcom/SRM-Cmdlets-master/SRM-Cmdlets-master/README.md @@ -0,0 +1,81 @@ +# SRM PowerCLI Cmdlets + +Helper functions for working with VMware SRM 6.5 with PowerCLI 6.5.1 or later. PowerShell 5.0 and above is required. + +This module is provided for illustrative/educational purposes to explain how the PowerCLI access to the SRM public API can be used. + +## Getting Started + +### Getting the SRM cmdlets + +The latest version of the software can be cloned from the git repository: + + git clone https://github.com/benmeadowcroft/SRM-Cmdlets.git + +Or downloaded as a [zip file](https://github.com/benmeadowcroft/SRM-Cmdlets/archive/master.zip). + +Specific releases (compatible with earlier PowerCLI and SRM versions) can be downloaded via the [release page](https://github.com/benmeadowcroft/SRM-Cmdlets/releases). + +### Deploy SRM-Cmdlets module + +After cloning (or downloading and extracting) the PowerShell module, you can import the module into your current PowerShell session by by passing the path to `Meadowcroft.Srm.psd1` to the `Import-Module` cmdlet, e.g.: + + Import-Module -Name .\SRM-Cmdlets\Meadowcroft.Srm.psd1 + +You can also install the module into the PowerShell path so it can be loaded implicitly. See [Microsoft's Installing Modules instructions](http://msdn.microsoft.com/en-us/library/dd878350) for more details on how to do this. + +The module uses the default prefix of `Srm` for the custom functions it defines. This can be overridden when importing the module by setting the value of the `-Prefix` parameter when calling `Import-Module`. + +### Connecting to SRM + +After installing the module the next step is to connect to the SRM server. Details of how to do this are located in the [PowerCLI 6.5.1 User's Guide](http://pubs.vmware.com/vsphere-65/topic/com.vmware.powercli.ug.doc/GUID-A5F206CF-264D-4565-8CB9-4ED1C337053F.html) + + $credential = Get-Credential + Connect-VIServer -Server vc-a.example.com -Credential $credential + Connect-SrmServer -Credential $credential -RemoteCredential $credential + +At this point we've just been using the cmdlets provided by PowerCLI, the PowerCLI documentation also provides some examples of how to call the SRM API to perform various tasks. In the rest of this introduction we'll perform some of those tasks using the custom functions defined in this project. + +### Report the Protected Virtual Machines and Their Protection Groups + +Goal: Create a simple report listing the VMs protected by SRM and the protection group they belong to. + + Get-SrmProtectionGroup | %{ + $pg = $_ + Get-SrmProtectedVM -ProtectionGroup $pg } | %{ + $output = "" | select VmName, PgName + $output.VmName = $_.Vm.Name + $output.PgName = $pg.GetInfo().Name + $output + } | Format-Table @{Label="VM Name"; Expression={$_.VmName} }, + @{Label="Protection group name"; Expression={$_.PgName} + } + +### Report the Last Recovery Plan Test + +Goal: Create a simple report listing the state of the last test of a recovery plan + + Get-SrmRecoveryPlan | %{ $_ | + Get-SrmRecoveryPlanResult -RecoveryMode Test | select -First 1 + } | Select Name, StartTime, RunMode, ResultState | Format-Table + + +### Execute a Recovery Plan Test + +Goal: for a specific recovery plan, execute a test failover. Note the "local" SRM server we are connected to should be the recovery site in order for this to be successful. + + Get-SrmRecoveryPlan -Name "Name of Plan" | Start-SrmRecoveryPlan -RecoveryMode Test + +### Export the Detailed XML Report of the Last Recovery Plan Workflow + +Goal: get the XML report of the last recovery plan execution for a specific recovery plan. + + Get-SrmRecoveryPlan -Name "Name of Plan" | Get-SrmRecoveryPlanResult | + select -First 1 | Export-SrmRecoveryPlanResultAsXml + +### Protect a Replicated VM + +Goal: Take a VM replicated using vSphere Replication or Array Based Replication, add it to an appropriate protection group and configure it for protection + + $pg = Get-SrmProtectionGroup "Name of Protection Group" + Get-VM vm-01a | Protect-SrmVM -ProtectionGroup $pg diff --git a/ServiceNow-CHGRequest.ps1 b/ServiceNow-CHGRequest.ps1 new file mode 100644 index 0000000..1b5d3d4 --- /dev/null +++ b/ServiceNow-CHGRequest.ps1 @@ -0,0 +1,33 @@ +$VMHostFQDNs = @( + 'itdvmmdntest07.nd.gov' +) + +foreach ($VMHostFQDN in $VMHostFQDNs) { + $VMHostName = $VMHostFQDN.Split('.')[0] + #$CmdbCi = Get-ITDServiceNowRecord -Table cmdb_ci_server -Filter "name=$VMHostName" + + $NewITDServiceNowChangeRequestParams = @{ + RequestedByUsername = 'zmeier'; + #ConfigurationItemSysId = $CmdbCi.sys_id; + Category = 'Systems Platforms - Systems'; + Subcategory = 'VMware'; + Impact = 2; + Priority = 2; + ShortDescription = "Upgrade $VMHostFQDN to vSphere 8.0 U3f, installing prerequisite firmware updates HPE Synergy 2025.05.01"; + Description = "Upgrade $VMHostFQDN to vSphere 8.0 U3f, remediation for VMSA-2025-0013"; + Justification = "Firmware updates. Security updates. Bug fixes."; + Implementation = "Evacuate all VMs from $VMHostFQDN. Install new firmware version 2025.05.01. Upgrade vSphere to 8.0 U3f. Apply VMware Host Profiles"; + RiskImpactAnalysis = "Low, Running virtual machines will be evacuated before update process begins."; + BackoutPlan = "If the upgrade fails, revert to previous firmware version and vSphere version through manual process."; + TestPlan = "Sandbox environment has been tested with this upgrade. No issues were found."; + WhoIsImpacted = ""; + StartTime = (Get-Date -Year 2025 -Month 11 -Day 7) + EndTime = (Get-Date -Year 2025 -Month 11 -Day 7).AddHours(8); + AssignmentGroup = 'NDIT-Computer Systems Windows'; + ChangeManagerUsername = 'khellman'; + ChangeCoordinatorUsername = 'mlaverdure'; + AssignedToUsername = 'zmeier'; + } + + $CHG = New-ITDServiceNowChangeRequest @NewITDServiceNowChangeRequestParams +} \ No newline at end of file diff --git a/ServiceNow-GetRITM.ps1 b/ServiceNow-GetRITM.ps1 new file mode 100644 index 0000000..d494ddc --- /dev/null +++ b/ServiceNow-GetRITM.ps1 @@ -0,0 +1,65 @@ +$Month = 7 +26..26 | ForEach-Object { + $Records = [System.Collections.ArrayList]@() + Write-Warning $_ + + $StartDate = Get-Date -Year 2023 -Month $Month -Day $_ -Hour 0 -Minute 0 -Second 0 + $EndDate = Get-Date -Year 2023 -Month $Month -Day $_ -Hour 23 -Minute 59 -Second 59 + + $filter = @('cat_item', '-eq', '89efc7041bb41dd04d8943b1b24bcb63'), + '-and', + @('opened_at', '-gt', $StartDate ), + '-and', + @('opened_at', '-lt', $EndDate ) + + $x = Get-ServiceNowRecord -Table 'Requested Item' -Filter $Filter -IncludeTotalCount -IncludeCustomVariable + + ForEach ($z in $x) { + $obj = [PSCustomObject]@{ + 'number' = $z.number; + 'sys_id' = $z.sys_id; + 'opened_at' = $z.opened_at; + 'requested_for' = $z.requested_for.display_value; + 'request_type' = ($z.CustomVariable | Where-Object Name -EQ 'request_type').Value + 'application_name' = ($z.CustomVariable | Where-Object Name -EQ 'application_name').Value + 'environment' = ($z.CustomVariable | Where-Object Name -EQ 'environment').Value + 'additional_comments' = ($z.CustomVariable | Where-Object Name -EQ 'additional_comments').Value + 'vm_work_needed' = ($z.CustomVariable | Where-Object Name -EQ 'vm_work_needed').Value + 'server_name' = ($z.CustomVariable | Where-Object Name -EQ 'server_name').Value + 'host_name' = ($z.CustomVariable | Where-Object Name -EQ 'host_name').Value + 'server_type' = ($z.CustomVariable | Where-Object Name -EQ 'server_type').Value + 'operating_system' = ($z.CustomVariable | Where-Object Name -EQ 'operating_system').Value + 'target_platform' = ($z.CustomVariable | Where-Object Name -EQ 'target_platform').Value + 'processors' = ($z.CustomVariable | Where-Object Name -EQ 'processors').Value + 'memory_gb' = ($z.CustomVariable | Where-Object Name -EQ 'memory_gb').Value + 'cidr_block' = ($z.CustomVariable | Where-Object Name -EQ 'cidr_block').Value + 'data_center' = ($z.CustomVariable | Where-Object Name -EQ 'data_center').Value + 'licensing_restrictions' = ($z.CustomVariable | Where-Object Name -EQ 'licensing_restrictions').Value + 'agency_name' = ($z.CustomVariable | Where-Object Name -EQ 'agency_name').Value + 'application_info' = ($z.CustomVariable | Where-Object Name -EQ 'application_info').Value + 'support_hours' = ($z.CustomVariable | Where-Object Name -EQ 'support_hours').Value + 'dr_protection' = ($z.CustomVariable | Where-Object Name -EQ 'dr_protection').Value + 'startup_priority' = ($z.CustomVariable | Where-Object Name -EQ 'startup_priority').Value + 'disk_1_os' = ($z.CustomVariable | Where-Object Name -EQ 'disk_1_os').Value + 'disk_2_swap_disk' = ($z.CustomVariable | Where-Object Name -EQ 'disk_2_swap_disk').Value + 'disk_3' = ($z.CustomVariable | Where-Object Name -EQ 'disk_3').Value + 'disk_4' = ($z.CustomVariable | Where-Object Name -EQ 'disk_4').Value + 'disk_5' = ($z.CustomVariable | Where-Object Name -EQ 'disk_5').Value + 'disk_6' = ($z.CustomVariable | Where-Object Name -EQ 'disk_6').Value + 'disk_7' = ($z.CustomVariable | Where-Object Name -EQ 'disk_7').Value + 'disk_8' = ($z.CustomVariable | Where-Object Name -EQ 'disk_8').Value + 'disk_9' = ($z.CustomVariable | Where-Object Name -EQ 'disk_9').Value + 'disk_10' = ($z.CustomVariable | Where-Object Name -EQ 'disk_10').Value + 'disk_11' = ($z.CustomVariable | Where-Object Name -EQ 'disk_11').Value + 'disk_12' = ($z.CustomVariable | Where-Object Name -EQ 'disk_12').Value + 'disk_13' = ($z.CustomVariable | Where-Object Name -EQ 'disk_13').Value + 'disk_14' = ($z.CustomVariable | Where-Object Name -EQ 'disk_14').Value + 'disk_15' = ($z.CustomVariable | Where-Object Name -EQ 'disk_15').Value + 'disk_16' = ($z.CustomVariable | Where-Object Name -EQ 'disk_16').Value + } + $null = $Records.Add($obj) + } + + #$Records = $Records + If ($Records) { $Records | Export-Csv "D:\OneDrive - State of North Dakota\RITMexport.csv" -Append -NoTypeInformation } +} \ No newline at end of file diff --git a/ServiceNow-GetRITMNDGOVUserId.ps1 b/ServiceNow-GetRITMNDGOVUserId.ps1 new file mode 100644 index 0000000..1102447 --- /dev/null +++ b/ServiceNow-GetRITMNDGOVUserId.ps1 @@ -0,0 +1,10 @@ +$Filter = 'requested_for=206d9e091b8898102653997fbd4bcbd4^ORrequested_for=1c1d16451b8898102653997fbd4bcb3b^ORrequested_for=2ddc5a811b8898102653997fbd4bcb3a^ORrequested_for=920d9e051b8898102653997fbd4bcb10^ORrequested_for=20287f77dbe0a8106f6ae415ca9619c7^ORrequested_for=e65fe8581b9518902653997fbd4bcb90^ORrequested_for=c74d5ec51b8898102653997fbd4bcb27^ORrequested_for=e74d9ec51b8898102653997fbd4bcbd1^ORrequested_for=fa7dde491b8898102653997fbd4bcbf0^ORrequested_for=fdad9e891b8898102653997fbd4bcbe2^ORrequested_for=d6adde891b8898102653997fbd4bcb7c^ORrequested_for=d62d52851b8898102653997fbd4bcba4^ORrequested_for=0ace50ad976f11d49ff29c14a253afc5^ORrequested_for=518dd2891b8898102653997fbd4bcb19^ORrequested_for=733d92c51b8898102653997fbd4bcbf7^cat_item=fc32b5ce1bba5cd02045fd16dc4bcb47' + +$x = Get-ITDServiceNowRecord -ItemType 'Request Item' -Filter $Filter -IncludeTotalCount -Verbose -IncludeCustomVariable + + +#$x[0] | Select-Object Number, @{n='RequestedBy';e={(Get-ITDServiceNowUser -SysId $_.v_requested_by.value).Name}}, opened_at, closed_at, user_id + +$x | Select-Object Number, @{n='RequestedFor';e={(Get-ITDServiceNowUser -SysId $_.requested_for.value).Name}}, @{n='v_type';e={$_.customvariable.v_type.value}}, opened_at, closed_at, @{n='user_id';e={$_.customvariable.user_id.value}} -ov z + +$z| export-csv "D:\ADServiceAccountHistory.csv" \ No newline at end of file diff --git a/ServiceNow-GetRITMTaskAppServer.ps1 b/ServiceNow-GetRITMTaskAppServer.ps1 new file mode 100644 index 0000000..4acfa50 --- /dev/null +++ b/ServiceNow-GetRITMTaskAppServer.ps1 @@ -0,0 +1,94 @@ +$CurrentCsv = Import-Csv -Path "D:\OneDrive - State of North Dakota\RitmExportAppServer.csv" +$NewestRecord = $CurrentCsv | Sort-Object -Descending number | select -First 1 +[datetime]$StartDate = $NewestRecord.opened_at +#$StartDate = Get-date -Year 2020 -Month 1 -Day 1 +[datetime]$EndDate = Get-Date #-Year 2023 -Month 3 -Day 30 + +$filter = @('cat_item', '-eq', '89efc7041bb41dd04d8943b1b24bcb63'), +'-and', +@('opened_at', '-gt', $StartDate ), +'-and', +@('opened_at', '-lt', $EndDate ) + +$RecordSearch = Get-ServiceNowRecord -Table 'Requested Item' -Filter $Filter -IncludeTotalCount | Sort-Object Number +#$RecordSearch = Get-ServiceNowRecord -Table 'Requested Item' -number RITM0245487 + +$CurrentCsv = Import-Csv -Path "D:\OneDrive - State of North Dakota\RitmExportAppServer.csv" +ForEach ($Record in $RecordSearch) { + Write-Warning -Message ("Begin record " + $Record.number) + If ( @($CurrentCsv.number | where-object {$_ -eq $Record.Number}).count -gt 0) { + Write-Warning -Message ("Number " + $Record.Number + " already in csv") + # do nothing + } + Else { + #Write-Warning -Message $record.number + $RecordDetail = Get-ServiceNowRecord -Table 'Requested Item' -ID $Record.Number -IncludeCustomVariable + + ForEach ($Record in $RecordDetail) { + $RecordsToExport = [System.Collections.ArrayList]@() + $obj = [PSCustomObject][ordered]@{ + 'number' = $Record.number; + 'sys_id' = $Record.sys_id; + 'opened_at' = $Record.opened_at; + 'requested_for' = $Record.requested_for.display_value; + 'short_description' = $Record.short_description; + 'request_type' = ($Record.CustomVariable | Where-Object Name -EQ 'request_type').Value + 'application_name' = ($Record.CustomVariable | Where-Object Name -EQ 'application_name').Value + 'environment' = ($Record.CustomVariable | Where-Object Name -EQ 'environment').Value + 'additional_comments' = ($Record.CustomVariable | Where-Object Name -EQ 'additional_comments').Value + 'vm_work_needed' = ($Record.CustomVariable | Where-Object Name -EQ 'vm_work_needed').Value + 'server_name' = ($Record.CustomVariable | Where-Object Name -EQ 'server_name').Value + 'host_name' = ($Record.CustomVariable | Where-Object Name -EQ 'host_name').Value + 'server_type' = ($Record.CustomVariable | Where-Object Name -EQ 'server_type').Value + 'operating_system' = ($Record.CustomVariable | Where-Object Name -EQ 'operating_system').Value + 'target_platform' = ($Record.CustomVariable | Where-Object Name -EQ 'target_platform').Value + 'processors' = ($Record.CustomVariable | Where-Object Name -EQ 'processors').Value + 'memory_gb' = ($Record.CustomVariable | Where-Object Name -EQ 'memory_gb').Value + 'cidr_block' = ($Record.CustomVariable | Where-Object Name -EQ 'cidr_block').Value + 'data_center' = ($Record.CustomVariable | Where-Object Name -EQ 'data_center').Value + 'licensing_restrictions' = ($Record.CustomVariable | Where-Object Name -EQ 'licensing_restrictions').Value + 'agency_name' = ($Record.CustomVariable | Where-Object Name -EQ 'agency_name').Value + 'application_info' = ($Record.CustomVariable | Where-Object Name -EQ 'application_info').Value + 'support_hours' = ($Record.CustomVariable | Where-Object Name -EQ 'support_hours').Value + 'dr_protection' = ($Record.CustomVariable | Where-Object Name -EQ 'dr_protection').Value + 'startup_priority' = ($Record.CustomVariable | Where-Object Name -EQ 'startup_priority').Value + 'disk_1_os' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_1_os').Value + 'disk_2_swap_disk' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_2_swap_disk').Value + 'disk_3' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_3').Value + 'disk_4' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_4').Value + 'disk_5' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_5').Value + 'disk_6' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_6').Value + 'disk_7' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_7').Value + 'disk_8' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_8').Value + 'disk_9' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_9').Value + 'disk_10' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_10').Value + 'disk_11' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_11').Value + 'disk_12' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_12').Value + 'disk_13' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_13').Value + 'disk_14' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_14').Value + 'disk_15' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_15').Value + 'disk_16' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_16').Value + } + + ForEach ($Property in $Record.PSObject.Properties) { + If ($obj.PSObject.Properties.Name -match $Property.Name) { + #Write-Verbose -Message ("Property " + $Property.Name + " already in obj") + } + Else { + $obj | Add-Member -MemberType $Property.MemberType -Name $Property.Name -Value $Property.Value -TypeName $Property.TypeNameOfValue -Verbose + } + } + ForEach ($Property in $Record.CustomVariable) { + If ($obj.PSObject.Properties.Name -match $Property.Name) { + #Write-Verbose -Message ("Property " + $Property.Name + " already in obj") + } + Else { + $obj | Add-Member -MemberType NoteProperty -Name $Property.Name -Value $Property.Value + } + } + $null = $RecordsToExport.Add($obj) + If ($RecordsToExport) { $RecordsToExport | Export-Csv "D:\OneDrive - State of North Dakota\RitmExportAppServer.csv" -Append -NoTypeInformation -Force } + } + } +} + diff --git a/ServiceNow-GetRITMTaskStorage.ps1 b/ServiceNow-GetRITMTaskStorage.ps1 new file mode 100644 index 0000000..9318718 --- /dev/null +++ b/ServiceNow-GetRITMTaskStorage.ps1 @@ -0,0 +1,65 @@ +$CurrentCsv = Import-Csv -Path "D:\OneDrive - State of North Dakota\RitmExportStorage.csv" +$NewestRecord = $CurrentCsv | Sort-Object -Descending number | select -First 1 +[datetime]$StartDate = $NewestRecord.opened_at +#$StartDate = Get-date -Year 2020 -Month 1 -Day 1 +[datetime]$EndDate = Get-Date #-Year 2023 -Month 3 -Day 30 + +$filter = @('cat_item', '-eq', '7c2457ae1bbfc9d06bc5cb751a4bcb69'), +'-and', +@('opened_at', '-gt', $StartDate ), +'-and', +@('opened_at', '-lt', $EndDate ) + +$RecordSearch = Get-ServiceNowRecord -Table 'Requested Item' -Filter $Filter -IncludeTotalCount | Sort-Object Number + +$CurrentCsv = Import-Csv -Path "D:\OneDrive - State of North Dakota\RitmExportStorage.csv" +ForEach ($Record in $RecordSearch) { + Write-Warning -Message ("Begin record " + $Record.number) + If ( @($CurrentCsv.number | Where-Object { $_ -eq $Record.Number }).count -gt 0) { + Write-Warning -Message ("Number " + $Record.Number + " already in csv") + # do nothing + } + Else { + #Write-Warning -Message $record.number + $RecordDetail = Get-ServiceNowRecord -Table 'Requested Item' -ID $Record.Number -IncludeCustomVariable + + ForEach ($Record in $RecordDetail) { + $RecordsToExport = [System.Collections.ArrayList]@() + $obj = [PSCustomObject][ordered]@{ + 'number' = $Record.number; + 'sys_id' = $Record.sys_id; + 'opened_at' = $Record.opened_at; + 'requested_for' = $Record.requested_for.display_value; + 'short_description' = $Record.short_description; + 'description' = $Record.short_description; + 'additional_comments' = ($Record.CustomVariable | Where-Object Name -EQ 'additional_comments').Value + 'request_type' = ($Record.CustomVariable | Where-Object Name -EQ 'request_type').Value + 'array_name' = ($Record.CustomVariable | Where-Object Name -EQ 'array_name').Value + 'size' = ($Record.CustomVariable | Where-Object Name -EQ 'size').Value + 'units' = ($Record.CustomVariable | Where-Object Name -EQ 'units').Value + 'abr' = ($Record.CustomVariable | Where-Object Name -EQ 'abr').Value + 'volume_name' = ($Record.CustomVariable | Where-Object Name -EQ 'volume_name').Value + } + + ForEach ($Property in $Record.PSObject.Properties) { + If ($obj.PSObject.Properties.Name -match $Property.Name) { + #Write-Verbose -Message ("Property " + $Property.Name + " already in obj") + } + Else { + $obj | Add-Member -MemberType $Property.MemberType -Name $Property.Name -Value $Property.Value -TypeName $Property.TypeNameOfValue -Verbose + } + } + ForEach ($Property in $Record.CustomVariable) { + If ($obj.PSObject.Properties.Name -match $Property.Name) { + #Write-Verbose -Message ("Property " + $Property.Name + " already in obj") + } + Else { + $obj | Add-Member -MemberType NoteProperty -Name $Property.Name -Value $Property.Value + } + } + $null = $RecordsToExport.Add($obj) + If ($RecordsToExport) { $RecordsToExport | Export-Csv "D:\OneDrive - State of North Dakota\RitmExportStorage.csv" -Append -NoTypeInformation -Force } + } + } +} + diff --git a/ServiceNow-RitmDB.ps1 b/ServiceNow-RitmDB.ps1 new file mode 100644 index 0000000..ea116eb --- /dev/null +++ b/ServiceNow-RitmDB.ps1 @@ -0,0 +1,511 @@ +# Configure variables below for connecting to the SQL database +################################################ +$CSVFileName = "D:\OneDrive - State of North Dakota\ServiceNow\RitmDump-Application Server.csv" +$SQLInstance = "itdintsql22p1.nd.gov\intsql22p1" +$SQLDatabase = "ITD-Systems-Automation" +$SQLTable = "ServiceNow_RitmDump_ApplicationServerMK2" +$SQLTempDatabase = "ITD-Systems-Automation" +$SQLTempTable = "ServiceNow_RitmDump_ApplicationServerMK2_temp" +############################################################################################ +# Nothing to change below this line, comments provided if you need/want to change anything +############################################################################################ +############################################## +# Prompting for SQL credentials +############################################## +#$SQLCredentials = Get-Credential -Message "Enter your SQL username & password" +#$SQLUsername = $SQLCredentials.UserName +#$SQLPassword = $SQLCredentials.GetNetworkCredential().Password +$SQLCredentials = $PrvCred +############################################## +# Start of time taken benchmark +############################################## +$Start = Get-Date +############################################## +# Checking if SqlServer module is already installed, if not installing it +############################################## +$SQLModuleCheck = Get-Module -ListAvailable SqlServer +if ($SQLModuleCheck -eq $null) { + Write-Host "SqlServer Module Not Found - Installing" + # Not installed, trusting PS Gallery to remove prompt on install + Set-PSRepository -Name PSGallery -InstallationPolicy Trusted + # Installing module + Install-Module -Name SqlServer –Scope CurrentUser -Confirm:$false -AllowClobber +} +############################################## +# Importing SqlServer module +############################################## +Import-Module SqlServer +############################################## +# Creating Temp SQL Table +############################################## +"Creating SQL Table $SQLTempTable for CSV Import" +$SQLCreateTempTable = "USE [ITD-Systems-Automation] +CREATE TABLE $SQLTempTable ( + sys_id char(32) PRIMARY KEY, + number char(11), + opened_at datetime, + requested_for varchar(255), + sys_updated_on datetime, + short_description varchar(max), + active varchar(255), + activity_due varchar(255), + additional_assignee_list varchar(255), + additional_comments varchar(max), + add_change_disaster_recovery varchar(255), + agency_name varchar(255), + application_info varchar(255), + application_name varchar(255), + approval_history varchar(max), + assigned_to varchar(255), + assignment_group varchar(255), + backordered varchar(255), + billable varchar(255), + business_duration varchar(255), + business_service varchar(255), + calendar_duration varchar(255), + cat_item varchar(255), + cat_item_display_name varchar(255), + cidr_block varchar(255), + closed_at datetime, + closed_by varchar(255), + close_notes varchar(max), + cmdb_ci varchar(255), + comments varchar(max), + configuration_item varchar(255), + contact_type varchar(255), + contract varchar(255), + correlation_display varchar(255), + correlation_id varchar(255), + data_center varchar(255), + disaster_recovery_requirements varchar(255), + disk_10 varchar(255), + disk_11 varchar(255), + disk_12 varchar(255), + disk_13 varchar(255), + disk_14 varchar(255), + disk_15 varchar(255), + disk_16 varchar(255), + disk_1_os varchar(255), + disk_2_swap_disk varchar(255), + disk_3 varchar(255), + disk_4 varchar(255), + disk_5 varchar(255), + disk_6 varchar(255), + disk_7 varchar(255), + disk_8 varchar(255), + disk_9 varchar(255), + dr_protection varchar(255), + due_date varchar(255), + environment varchar(255), + escalation varchar(255), + estimated_delivery datetime, + expected_start varchar(255), + follow_up varchar(255), + group_list varchar(255), + host_name varchar(255), + impact varchar(255), + knowledge varchar(255), + licensing_restrictions varchar(255), + location varchar(255), + made_sla varchar(255), + memory_gb varchar(255), + opened_by varchar(255), + operating_system varchar(255), + order_guide varchar(255), + parent varchar(255), + pa_zone varchar(255), + price varchar(255), + priority varchar(255), + processors varchar(255), + quantity_sourced varchar(255), + reassignment_count varchar(255), + received varchar(255), + recurring_frequency varchar(255), + recurring_price varchar(255), + replaces_vm varchar(255), + request_type varchar(255), + required_date varchar(255), + require_hosting_quote varchar(255), + route_reason varchar(255), + sc_catalog varchar(255), + secure varchar(255), + server_name varchar(255), + server_type varchar(255), + service_offering varchar(255), + skills varchar(255), + sla_due varchar(255), + special_instructions varchar(255), + stage varchar(255), + startup_priority varchar(255), + state varchar(255), + support_hours varchar(255), + sys_class_name varchar(255), + sys_created_by varchar(255), + sys_created_on datetime, + sys_domain varchar(255), + sys_domain_path varchar(255), + sys_mod_count varchar(255), + sys_tags varchar(255), + sys_updated_by varchar(255), + target_os_version_linux varchar(255), + target_os_version_windows varchar(255), + target_platform varchar(255), + task_effective_number varchar(255), + team_lead varchar(255), + time_worked varchar(255), + universal_request varchar(255), + upon_approval varchar(255), + upon_reject varchar(255), + urgency varchar(255), + user_input varchar(255), + u_approval_flag varchar(255), + u_change_incident varchar(255), + u_effective_date varchar(255), + u_on_hold_reason varchar(255), + vlan_id varchar(255), + vm_work_needed varchar(255), + v_alt_contact varchar(255), + v_approval_charge_code varchar(255), + v_approval_department varchar(255), + v_approval_department_code varchar(255), + v_approval_division varchar(255), + v_approval_division_code varchar(255), + v_manager varchar(255), + v_requested_by varchar(255), + v_requested_for varchar(255), + v_user_email varchar(255), + v_user_in_servicenow varchar(255), + v_user_phone varchar(255), + watch_list varchar(255), + work_end varchar(255), + work_notes varchar(max), + work_start varchar(255) +);" +#Invoke-Sqlcmd -Query $SQLCreateTempTable -ServerInstance $SQLInstance -Username $SQLUsername -Password $SQLPassword +#Invoke-ITDSqlCmdJob -ServerInstance $SInstance -Database ITD-Systems-Automation -Credential $PrvCred -Query +Invoke-ITDSqlCmdJob -ServerInstance $SqlInstance -Database ITD-Systems-Automation -Credential $PrvCred -Query $SQLCreateTempTable +############################################## +# Importing CSV and processing data +############################################## +$CSVImport = Import-Csv -Path $CSVFileName +$CSVRowCount = $CSVImport.Count +############################################## +# ForEach CSV Line Inserting a row into the Temp SQL table +############################################## +"Inserting $CSVRowCount rows from CSV into SQL Table $SQLTempTable" +ForEach ($CSVLine in $CSVImport) { + Write-Warning -Message ("Start " + $CSVLine.number) + # Setting variables for the CSV line, ADD ALL 170 possible CSV columns here + $sys_id = $CSVLine.sys_id + $number = $CSVLine.number + $opened_at = $CSVLine.opened_at + $requested_for = $CSVLine.requested_for + $sys_updated_on = $CSVLine.sys_updated_on + $short_description = $CSVLine.short_description + $active = $CSVLine.active + $activity_due = $CSVLine.activity_due + $additional_assignee_list = $CSVLine.additional_assignee_list + $additional_comments = $CSVLine.additional_comments + $add_change_disaster_recovery = $CSVLine.add_change_disaster_recovery + $agency_name = $CSVLine.agency_name + $application_info = $CSVLine.application_info + $application_name = $CSVLine.application_name + $approval_history = $CSVLine.approval_history + $assigned_to = $CSVLine.assigned_to + $assignment_group = $CSVLine.assignment_group + $backordered = $CSVLine.backordered + $billable = $CSVLine.billable + $business_duration = $CSVLine.business_duration + $business_service = $CSVLine.business_service + $calendar_duration = $CSVLine.calendar_duration + $cat_item = $CSVLine.cat_item + $cat_item_display_name = $CSVLine.cat_item_display_name + $cidr_block = $CSVLine.cidr_block + $closed_at = $CSVLine.closed_at + $closed_by = $CSVLine.closed_by + $close_notes = $CSVLine.close_notes + $cmdb_ci = $CSVLine.cmdb_ci + $comments = $CSVLine.comments + $configuration_item = $CSVLine.configuration_item + $contact_type = $CSVLine.contact_type + $contract = $CSVLine.contract + $correlation_display = $CSVLine.correlation_display + $correlation_id = $CSVLine.correlation_id + $data_center = $CSVLine.data_center + $disaster_recovery_requirements = $CSVLine.disaster_recovery_requirements + $disk_10 = $CSVLine.disk_10 + $disk_11 = $CSVLine.disk_11 + $disk_12 = $CSVLine.disk_12 + $disk_13 = $CSVLine.disk_13 + $disk_14 = $CSVLine.disk_14 + $disk_15 = $CSVLine.disk_15 + $disk_16 = $CSVLine.disk_16 + $disk_1_os = $CSVLine.disk_1_os + $disk_2_swap_disk = $CSVLine.disk_2_swap_disk + $disk_3 = $CSVLine.disk_3 + $disk_4 = $CSVLine.disk_4 + $disk_5 = $CSVLine.disk_5 + $disk_6 = $CSVLine.disk_6 + $disk_7 = $CSVLine.disk_7 + $disk_8 = $CSVLine.disk_8 + $disk_9 = $CSVLine.disk_9 + $dr_protection = $CSVLine.dr_protection + $due_date = $CSVLine.due_date + $environment = $CSVLine.environment + $escalation = $CSVLine.escalation + $estimated_delivery = $CSVLine.estimated_delivery + $expected_start = $CSVLine.expected_start + $follow_up = $CSVLine.follow_up + $group_list = $CSVLine.group_list + $host_name = $CSVLine.host_name + $impact = $CSVLine.impact + $knowledge = $CSVLine.knowledge + $licensing_restrictions = $CSVLine.licensing_restrictions + $location = $CSVLine.location + $made_sla = $CSVLine.made_sla + $memory_gb = $CSVLine.memory_gb + $opened_by = $CSVLine.opened_by + $operating_system = $CSVLine.operating_system + $order_guide = $CSVLine.order_guide + $parent = $CSVLine.parent + $pa_zone = $CSVLine.pa_zone + $price = $CSVLine.price + $priority = $CSVLine.priority + $processors = $CSVLine.processors + $quantity_sourced = $CSVLine.quantity_sourced + $reassignment_count = $CSVLine.reassignment_count + $received = $CSVLine.received + $recurring_frequency = $CSVLine.recurring_frequency + $recurring_price = $CSVLine.recurring_price + $replaces_vm = $CSVLine.replaces_vm + $request_type = $CSVLine.request_type + $required_date = $CSVLine.required_date + $require_hosting_quote = $CSVLine.require_hosting_quote + $route_reason = $CSVLine.route_reason + $sc_catalog = $CSVLine.sc_catalog + $secure = $CSVLine.secure + $server_name = $CSVLine.server_name + $server_type = $CSVLine.server_type + $service_offering = $CSVLine.service_offering + $skills = $CSVLine.skills + $sla_due = $CSVLine.sla_due + $special_instructions = $CSVLine.special_instructions + $stage = $CSVLine.stage + $startup_priority = $CSVLine.startup_priority + $state = $CSVLine.state + $support_hours = $CSVLine.support_hours + $sys_class_name = $CSVLine.sys_class_name + $sys_created_by = $CSVLine.sys_created_by + $sys_created_on = $CSVLine.sys_created_on + $sys_domain = $CSVLine.sys_domain + $sys_domain_path = $CSVLine.sys_domain_path + $sys_mod_count = $CSVLine.sys_mod_count + $sys_tags = $CSVLine.sys_tags + $sys_updated_by = $CSVLine.sys_updated_by + $target_os_version_linux = $CSVLine.target_os_version_linux + $target_os_version_windows = $CSVLine.target_os_version_windows + $target_platform = $CSVLine.target_platform + $task_effective_number = $CSVLine.task_effective_number + $team_lead = $CSVLine.team_lead + $time_worked = $CSVLine.time_worked + $universal_request = $CSVLine.universal_request + $upon_approval = $CSVLine.upon_approval + $upon_reject = $CSVLine.upon_reject + $urgency = $CSVLine.urgency + $user_input = $CSVLine.user_input + $u_approval_flag = $CSVLine.u_approval_flag + $u_change_incident = $CSVLine.u_change_incident + $u_effective_date = $CSVLine.u_effective_date + $u_on_hold_reason = $CSVLine.u_on_hold_reason + $vlan_id = $CSVLine.vlan_id + $vm_work_needed = $CSVLine.vm_work_needed + $v_alt_contact = $CSVLine.v_alt_contact + $v_approval_charge_code = $CSVLine.v_approval_charge_code + $v_approval_department = $CSVLine.v_approval_department + $v_approval_department_code = $CSVLine.v_approval_department_code + $v_approval_division = $CSVLine.v_approval_division + $v_approval_division_code = $CSVLine.v_approval_division_code + $v_manager = $CSVLine.v_manager + $v_requested_by = $CSVLine.v_requested_by + $v_requested_for = $CSVLine.v_requested_for + $v_user_email = $CSVLine.v_user_email + $v_user_in_servicenow = $CSVLine.v_user_in_servicenow + $v_user_phone = $CSVLine.v_user_phone + $watch_list = $CSVLine.watch_list + $work_end = $CSVLine.work_end + $work_notes = $CSVLine.work_notes + $work_start = $CSVLine.work_start + + $SQLInsert = "USE [$SQLTempDatabase] +INSERT INTO $SQLTempTable (sys_id, number, opened_at, requested_for, sys_updated_on, short_description, active, activity_due, additional_assignee_list, additional_comments, add_change_disaster_recovery, agency_name, application_info, application_name, approval_history, assigned_to, assignment_group, backordered, billable, business_duration, business_service, calendar_duration, cat_item, cat_item_display_name, cidr_block, closed_at, closed_by, close_notes, cmdb_ci, comments, configuration_item, contact_type, contract, correlation_display, correlation_id, data_center, disaster_recovery_requirements, disk_10, disk_11, disk_12, disk_13, disk_14, disk_15, disk_16, disk_1_os, disk_2_swap_disk, disk_3, disk_4, disk_5, disk_6, disk_7, disk_8, disk_9, dr_protection, due_date, environment, escalation, estimated_delivery, expected_start, follow_up, group_list, host_name, impact, knowledge, licensing_restrictions, location, made_sla, memory_gb, opened_by, operating_system, order_guide, parent, pa_zone, price, priority, processors, quantity_sourced, reassignment_count, received, recurring_frequency, recurring_price, replaces_vm, request_type, required_date, require_hosting_quote, route_reason, sc_catalog, secure, server_name, server_type, service_offering, skills, sla_due, special_instructions, stage, startup_priority, state, support_hours, sys_class_name, sys_created_by, sys_created_on, sys_domain, sys_domain_path, sys_mod_count, sys_tags, sys_updated_by, target_os_version_linux, target_os_version_windows, target_platform, task_effective_number, team_lead, time_worked, universal_request, upon_approval, upon_reject, urgency, user_input, u_approval_flag, u_change_incident, u_effective_date, u_on_hold_reason, vlan_id, vm_work_needed, v_alt_contact, v_approval_charge_code, v_approval_department, v_approval_department_code, v_approval_division, v_approval_division_code, v_manager, v_requested_by, v_requested_for, v_user_email, v_user_in_servicenow, v_user_phone, watch_list, work_end, work_notes, work_start) +VALUES('$sys_id', '$number', '$opened_at', '$requested_for', '$sys_updated_on', '$short_description', '$active', '$activity_due', '$additional_assignee_list', '$additional_comments', '$add_change_disaster_recovery', '$agency_name', '$application_info', '$application_name', '$approval_history', '$assigned_to', '$assignment_group', '$backordered', '$billable', '$business_duration', '$business_service', '$calendar_duration', '$cat_item', '$cat_item_display_name', '$cidr_block', '$closed_at', '$closed_by', '$close_notes', '$cmdb_ci', '$comments', '$configuration_item', '$contact_type', '$contract', '$correlation_display', '$correlation_id', '$data_center', '$disaster_recovery_requirements', '$disk_10', '$disk_11', '$disk_12', '$disk_13', '$disk_14', '$disk_15', '$disk_16', '$disk_1_os', '$disk_2_swap_disk', '$disk_3', '$disk_4', '$disk_5', '$disk_6', '$disk_7', '$disk_8', '$disk_9', '$dr_protection', '$due_date', '$environment', '$escalation', '$estimated_delivery', '$expected_start', '$follow_up', '$group_list', '$host_name', '$impact', '$knowledge', '$licensing_restrictions', '$location', '$made_sla', '$memory_gb', '$opened_by', '$operating_system', '$order_guide', '$parent', '$pa_zone', '$price', '$priority', '$processors', '$quantity_sourced', '$reassignment_count', '$received', '$recurring_frequency', '$recurring_price', '$replaces_vm', '$request_type', '$required_date', '$require_hosting_quote', '$route_reason', '$sc_catalog', '$secure', '$server_name', '$server_type', '$service_offering', '$skills', '$sla_due', '$special_instructions', '$stage', '$startup_priority', '$state', '$support_hours', '$sys_class_name', '$sys_created_by', '$sys_created_on', '$sys_domain', '$sys_domain_path', '$sys_mod_count', '$sys_tags', '$sys_updated_by', '$target_os_version_linux', '$target_os_version_windows', '$target_platform', '$task_effective_number', '$team_lead', '$time_worked', '$universal_request', '$upon_approval', '$upon_reject', '$urgency', '$user_input', '$u_approval_flag', '$u_change_incident', '$u_effective_date', '$u_on_hold_reason', '$vlan_id', '$vm_work_needed', '$v_alt_contact', '$v_approval_charge_code', '$v_approval_department', '$v_approval_department_code', '$v_approval_division', '$v_approval_division_code', '$v_manager', '$v_requested_by', '$v_requested_for', '$v_user_email', '$v_user_in_servicenow', '$v_user_phone', '$watch_list', '$work_end', '$work_notes', '$work_start');" + # Running the INSERT Query + #Invoke-Sqlcmd -Query $SQLInsert -ServerInstance $SQLInstance -Username $SQLUsername -Password $SQLPassword + Invoke-ITDSqlCmdJob -ServerInstance $SQLInstance -Database $SQLDatabase -Query $SQLInsert -Credential $PrvCred + # End of ForEach CSV line below +} +# End of ForEach CSV line above +############################################## +# Merging data from Temp Table to Target Table using SQL MERGE +############################################## +"Merging SQL Table Data from $SQLTempTable to $SQLTable" +# For more info, I.E to add DELETE as part of the MERGE, read: https://www.essentialsql.com/introduction-merge-statement/ +$SQLMerge = "MERGE [$SQLDatabase].[dbo].[$SQLTable] Target +USING [$SQLTempDatabase].[dbo].[$SQLTempTable] Source +ON (Target.sys_id = Source.sys_id) +WHEN MATCHED + THEN UPDATE + SET Target.sys_id = Source.sys_id, + Target.number = Source.number, + Target.opened_at = Source.opened_at, + Target.requested_for = Source.requested_for, + Target.sys_updated_on = Source.sys_updated_on, + Target.short_description = Source.short_description, + Target.active = Source.active, + Target.activity_due = Source.activity_due, + Target.additional_assignee_list = Source.additional_assignee_list, + Target.additional_comments = Source.additional_comments, + Target.add_change_disaster_recovery = Source.add_change_disaster_recovery, + Target.agency_name = Source.agency_name, + Target.application_info = Source.application_info, + Target.application_name = Source.application_name, + Target.approval_history = Source.approval_history, + Target.assigned_to = Source.assigned_to, + Target.assignment_group = Source.assignment_group, + Target.backordered = Source.backordered, + Target.billable = Source.billable, + Target.business_duration = Source.business_duration, + Target.business_service = Source.business_service, + Target.calendar_duration = Source.calendar_duration, + Target.cat_item = Source.cat_item, + Target.cat_item_display_name = Source.cat_item_display_name, + Target.cidr_block = Source.cidr_block, + Target.closed_at = Source.closed_at, + Target.closed_by = Source.closed_by, + Target.close_notes = Source.close_notes, + Target.cmdb_ci = Source.cmdb_ci, + Target.comments = Source.comments, + Target.configuration_item = Source.configuration_item, + Target.contact_type = Source.contact_type, + Target.contract = Source.contract, + Target.correlation_display = Source.correlation_display, + Target.correlation_id = Source.correlation_id, + Target.data_center = Source.data_center, + Target.disaster_recovery_requirements = Source.disaster_recovery_requirements, + Target.disk_10 = Source.disk_10, + Target.disk_11 = Source.disk_11, + Target.disk_12 = Source.disk_12, + Target.disk_13 = Source.disk_13, + Target.disk_14 = Source.disk_14, + Target.disk_15 = Source.disk_15, + Target.disk_16 = Source.disk_16, + Target.disk_1_os = Source.disk_1_os, + Target.disk_2_swap_disk = Source.disk_2_swap_disk, + Target.disk_3 = Source.disk_3, + Target.disk_4 = Source.disk_4, + Target.disk_5 = Source.disk_5, + Target.disk_6 = Source.disk_6, + Target.disk_7 = Source.disk_7, + Target.disk_8 = Source.disk_8, + Target.disk_9 = Source.disk_9, + Target.dr_protection = Source.dr_protection, + Target.due_date = Source.due_date, + Target.environment = Source.environment, + Target.escalation = Source.escalation, + Target.estimated_delivery = Source.estimated_delivery, + Target.expected_start = Source.expected_start, + Target.follow_up = Source.follow_up, + Target.group_list = Source.group_list, + Target.host_name = Source.host_name, + Target.impact = Source.impact, + Target.knowledge = Source.knowledge, + Target.licensing_restrictions = Source.licensing_restrictions, + Target.location = Source.location, + Target.made_sla = Source.made_sla, + Target.memory_gb = Source.memory_gb, + Target.opened_by = Source.opened_by, + Target.operating_system = Source.operating_system, + Target.order_guide = Source.order_guide, + Target.parent = Source.parent, + Target.pa_zone = Source.pa_zone, + Target.price = Source.price, + Target.priority = Source.priority, + Target.processors = Source.processors, + Target.quantity_sourced = Source.quantity_sourced, + Target.reassignment_count = Source.reassignment_count, + Target.received = Source.received, + Target.recurring_frequency = Source.recurring_frequency, + Target.recurring_price = Source.recurring_price, + Target.replaces_vm = Source.replaces_vm, + Target.request_type = Source.request_type, + Target.required_date = Source.required_date, + Target.require_hosting_quote = Source.require_hosting_quote, + Target.route_reason = Source.route_reason, + Target.sc_catalog = Source.sc_catalog, + Target.secure = Source.secure, + Target.server_name = Source.server_name, + Target.server_type = Source.server_type, + Target.service_offering = Source.service_offering, + Target.skills = Source.skills, + Target.sla_due = Source.sla_due, + Target.special_instructions = Source.special_instructions, + Target.stage = Source.stage, + Target.startup_priority = Source.startup_priority, + Target.state = Source.state, + Target.support_hours = Source.support_hours, + Target.sys_class_name = Source.sys_class_name, + Target.sys_created_by = Source.sys_created_by, + Target.sys_created_on = Source.sys_created_on, + Target.sys_domain = Source.sys_domain, + Target.sys_domain_path = Source.sys_domain_path, + Target.sys_mod_count = Source.sys_mod_count, + Target.sys_tags = Source.sys_tags, + Target.sys_updated_by = Source.sys_updated_by, + Target.target_os_version_linux = Source.target_os_version_linux, + Target.target_os_version_windows = Source.target_os_version_windows, + Target.target_platform = Source.target_platform, + Target.task_effective_number = Source.task_effective_number, + Target.team_lead = Source.team_lead, + Target.time_worked = Source.time_worked, + Target.universal_request = Source.universal_request, + Target.upon_approval = Source.upon_approval, + Target.upon_reject = Source.upon_reject, + Target.urgency = Source.urgency, + Target.user_input = Source.user_input, + Target.u_approval_flag = Source.u_approval_flag, + Target.u_change_incident = Source.u_change_incident, + Target.u_effective_date = Source.u_effective_date, + Target.u_on_hold_reason = Source.u_on_hold_reason, + Target.vlan_id = Source.vlan_id, + Target.vm_work_needed = Source.vm_work_needed, + Target.v_alt_contact = Source.v_alt_contact, + Target.v_approval_charge_code = Source.v_approval_charge_code, + Target.v_approval_department = Source.v_approval_department, + Target.v_approval_department_code = Source.v_approval_department_code, + Target.v_approval_division = Source.v_approval_division, + Target.v_approval_division_code = Source.v_approval_division_code, + Target.v_manager = Source.v_manager, + Target.v_requested_by = Source.v_requested_by, + Target.v_requested_for = Source.v_requested_for, + Target.v_user_email = Source.v_user_email, + Target.v_user_in_servicenow = Source.v_user_in_servicenow, + Target.v_user_phone = Source.v_user_phone, + Target.watch_list = Source.watch_list, + Target.work_end = Source.work_end, + Target.work_notes = Source.work_notes, + Target.work_start = Source.work_start + +WHEN NOT MATCHED BY TARGET +THEN INSERT (sys_id, number, opened_at, requested_for, sys_updated_on, short_description, active, activity_due, additional_assignee_list, additional_comments, add_change_disaster_recovery, agency_name, application_info, application_name, approval_history, assigned_to, assignment_group, backordered, billable, business_duration, business_service, calendar_duration, cat_item, cat_item_display_name, cidr_block, closed_at, closed_by, close_notes, cmdb_ci, comments, configuration_item, contact_type, contract, correlation_display, correlation_id, data_center, disaster_recovery_requirements, disk_10, disk_11, disk_12, disk_13, disk_14, disk_15, disk_16, disk_1_os, disk_2_swap_disk, disk_3, disk_4, disk_5, disk_6, disk_7, disk_8, disk_9, dr_protection, due_date, environment, escalation, estimated_delivery, expected_start, follow_up, group_list, host_name, impact, knowledge, licensing_restrictions, location, made_sla, memory_gb, opened_by, operating_system, order_guide, parent, pa_zone, price, priority, processors, quantity_sourced, reassignment_count, received, recurring_frequency, recurring_price, replaces_vm, request_type, required_date, require_hosting_quote, route_reason, sc_catalog, secure, server_name, server_type, service_offering, skills, sla_due, special_instructions, stage, startup_priority, state, support_hours, sys_class_name, sys_created_by, sys_created_on, sys_domain, sys_domain_path, sys_mod_count, sys_tags, sys_updated_by, target_os_version_linux, target_os_version_windows, target_platform, task_effective_number, team_lead, time_worked, universal_request, upon_approval, upon_reject, urgency, user_input, u_approval_flag, u_change_incident, u_effective_date, u_on_hold_reason, vlan_id, vm_work_needed, v_alt_contact, v_approval_charge_code, v_approval_department, v_approval_department_code, v_approval_division, v_approval_division_code, v_manager, v_requested_by, v_requested_for, v_user_email, v_user_in_servicenow, v_user_phone, watch_list, work_end, work_notes, work_start) + VALUES (Source.sys_id, Source.number, Source.opened_at, Source.requested_for, Source.sys_updated_on, Source.short_description, Source.active, Source.activity_due, Source.additional_assignee_list, Source.additional_comments, Source.add_change_disaster_recovery, Source.agency_name, Source.application_info, Source.application_name, Source.approval_history, Source.assigned_to, Source.assignment_group, Source.backordered, Source.billable, Source.business_duration, Source.business_service, Source.calendar_duration, Source.cat_item, Source.cat_item_display_name, Source.cidr_block, Source.closed_at, Source.closed_by, Source.close_notes, Source.cmdb_ci, Source.comments, Source.configuration_item, Source.contact_type, Source.contract, Source.correlation_display, Source.correlation_id, Source.data_center, Source.disaster_recovery_requirements, Source.disk_10, Source.disk_11, Source.disk_12, Source.disk_13, Source.disk_14, Source.disk_15, Source.disk_16, Source.disk_1_os, Source.disk_2_swap_disk, Source.disk_3, Source.disk_4, Source.disk_5, Source.disk_6, Source.disk_7, Source.disk_8, Source.disk_9, Source.dr_protection, Source.due_date, Source.environment, Source.escalation, Source.estimated_delivery, Source.expected_start, Source.follow_up, Source.group_list, Source.host_name, Source.impact, Source.knowledge, Source.licensing_restrictions, Source.location, Source.made_sla, Source.memory_gb, Source.opened_by, Source.operating_system, Source.order_guide, Source.parent, Source.pa_zone, Source.price, Source.priority, Source.processors, Source.quantity_sourced, Source.reassignment_count, Source.received, Source.recurring_frequency, Source.recurring_price, Source.replaces_vm, Source.request_type, Source.required_date, Source.require_hosting_quote, Source.route_reason, Source.sc_catalog, Source.secure, Source.server_name, Source.server_type, Source.service_offering, Source.skills, Source.sla_due, Source.special_instructions, Source.stage, Source.startup_priority, Source.state, Source.support_hours, Source.sys_class_name, Source.sys_created_by, Source.sys_created_on, Source.sys_domain, Source.sys_domain_path, Source.sys_mod_count, Source.sys_tags, Source.sys_updated_by, Source.target_os_version_linux, Source.target_os_version_windows, Source.target_platform, Source.task_effective_number, Source.team_lead, Source.time_worked, Source.universal_request, Source.upon_approval, Source.upon_reject, Source.urgency, Source.user_input, Source.u_approval_flag, Source.u_change_incident, Source.u_effective_date, Source.u_on_hold_reason, Source.vlan_id, Source.vm_work_needed, Source.v_alt_contact, Source.v_approval_charge_code, Source.v_approval_department, Source.v_approval_department_code, Source.v_approval_division, Source.v_approval_division_code, Source.v_manager, Source.v_requested_by, Source.v_requested_for, Source.v_user_email, Source.v_user_in_servicenow, Source.v_user_phone, Source.watch_list, Source.work_end, Source.work_notes, Source.work_start);" +#Invoke-Sqlcmd -Query $SQLMerge -ServerInstance $SQLInstance -Username $SQLUsername -Password $SQLPassword +Invoke-ITDSqlCmdJob -ServerInstance $SqlInstance -Database $SQLDatabase -Query $SQLMerge -Credential $PrvCred +############################################## +# Dropping Temp Table using SQL DROP +############################################## +"Dropping SQL Table $SQLTempTable as no longer needed" +$SQLDrop = "USE [$SQLTempDatabase] +DROP TABLE $SQLTempTable;" +#Invoke-Sqlcmd -Query $SQLDrop -ServerInstance $SQLInstance -Username $SQLUsername -Password $SQLPassword +Invoke-ITDSqlCmdJob -ServerInstance $SqlInstance -Database $SQLDatabase -Query $SQLDrop -Credential $PrvCred +############################################## \ No newline at end of file diff --git a/ServiceNow-RitmDumpMK2.ps1 b/ServiceNow-RitmDumpMK2.ps1 new file mode 100644 index 0000000..4d1ef42 --- /dev/null +++ b/ServiceNow-RitmDumpMK2.ps1 @@ -0,0 +1,151 @@ +# modified last hour block +#[datetime]$StartDate = (Get-Date -Minute 0 -Second 0).AddHours(-1) +#[datetime]$EndDate = (Get-Date -Minute 59 -Second 59).AddHours(-1) + +# modified yesterday +#[datetime]$StartDate = (Get-Date -Hour 0 -Minute 0 -Second 0).AddDays(-1) +#[datetime]$EndDate = (Get-Date -hour 23 -Minute 59 -Second 59).AddDays(-1) + +# modified 2023 +[datetime]$StartDate = (Get-Date -Year 2023 -Month 4 -Day 1 -Hour 0 -Minute 0 -Second 0).AddDays(-1) +[datetime]$EndDate = (Get-Date -Year 2023 -Month 5 -Day 31 -Hour 23 -Minute 59 -Second 59).AddDays(-1) + +# edit filter as needed +$Filter = @('cat_item', '-eq', '89efc7041bb41dd04d8943b1b24bcb63'), +'-and', +@('sys_updated_on', '-gt', $StartDate ), +'-and', +@('sys_updated_on', '-lt', $EndDate ) +#> + +$RecordSearch = Get-ServiceNowRecord -Table 'Requested Item' -Filter $Filter -IncludeTotalCount | select *, @{n = 'cat_item_display_name'; e = { $_.cat_item.display_value } } + +# TO-DO: loop each cat_item_display_name, and export to dedicated csv +$CatItemDisplayNames = ($RecordSearch | Select-Object -Unique cat_item_display_name).cat_item_display_name +ForEach ($CatItemDisplayName in $CatItemDisplayNames) { + Clear-Variable -Name RecordsToImport -ErrorAction SilentlyContinue + $RecordsToImport = $RecordSearch | Where-Object cat_item_display_name -EQ $CatItemDisplayName + $CsvPath = "D:\OneDrive - State of North Dakota\ServiceNow\RitmDump-$CatItemDisplayName.csv" + + Write-Warning -Message ($CatItemDisplayName + " records to import = " + $RecordsToImport.count) + $RecordsToExport = [System.Collections.ArrayList]@() + ForEach ($Record in $RecordsToImport) { + Write-Warning -Message ("Begin record " + $Record.number) + $RecordDetail = Get-ServiceNowRecord -Table 'Requested Item' -ID $Record.Number -IncludeCustomVariable + + $obj = [PSCustomObject][ordered]@{ + 'number' = $Record.number; + 'sys_id' = $Record.sys_id; + 'opened_at' = $Record.opened_at; + 'requested_for' = $Record.requested_for.display_value; + 'sys_updated_on' = $Record.sys_updated_on + 'short_description' = $Record.short_description; + } + + ForEach ($Property in $Record.PSObject.Properties) { + If ($obj.PSObject.Properties.Name -match $Property.Name) { + #Write-Verbose -Message ("Property " + $Property.Name + " already in obj") + } + Else { + # add missing default RITM property to new obj + $obj | Add-Member -MemberType $Property.MemberType -Name $Property.Name -Value $Property.Value -TypeName $Property.TypeNameOfValue -Verbose + } + } + ForEach ($Property in ($RecordDetail.CustomVariable | Sort-Object Name)) { + If ($obj.PSObject.Properties.Name -match $Property.Name) { + #Write-Verbose -Message ("Property " + $Property.Name + " already in obj") + } + Else { + # add missing custom variables to new obj + $obj | Add-Member -MemberType NoteProperty -Name $Property.Name -Value $Property.Value + } + }#> + $null = $RecordsToExport.Add($obj) + } + If ($RecordsToExport) { $RecordsToExport | Export-Csv $CsvPath -Append -NoTypeInformation -Force } +} + +<# +$CurrentCsv = Import-Csv -Path $CsvPath +ForEach ($Record in $RecordSearch) { + Write-Warning -Message ("Begin record " + $Record.number) + If ( @($CurrentCsv.number | Where-Object { $_ -eq $Record.Number }).count -gt 0) { + Write-Warning -Message ("Number " + $Record.Number + " already in csv") + # do nothing + } + Else { + #Write-Warning -Message $record.number + $RecordDetail = Get-ServiceNowRecord -Table 'Requested Item' -ID $Record.Number -IncludeCustomVariable + + ForEach ($Record in $RecordDetail) { + $RecordsToExport = [System.Collections.ArrayList]@() + $obj = [PSCustomObject][ordered]@{ + # get specific custom fields first, so the columns are on the left of csv + 'number' = $Record.number; + 'sys_id' = $Record.sys_id; + 'opened_at' = $Record.opened_at; + 'requested_for' = $Record.requested_for.display_value; + 'short_description' = $Record.short_description; + 'request_type' = ($Record.CustomVariable | Where-Object Name -EQ 'request_type').Value + 'application_name' = ($Record.CustomVariable | Where-Object Name -EQ 'application_name').Value + 'environment' = ($Record.CustomVariable | Where-Object Name -EQ 'environment').Value + 'additional_comments' = ($Record.CustomVariable | Where-Object Name -EQ 'additional_comments').Value + 'vm_work_needed' = ($Record.CustomVariable | Where-Object Name -EQ 'vm_work_needed').Value + 'server_name' = ($Record.CustomVariable | Where-Object Name -EQ 'server_name').Value + 'host_name' = ($Record.CustomVariable | Where-Object Name -EQ 'host_name').Value + 'server_type' = ($Record.CustomVariable | Where-Object Name -EQ 'server_type').Value + 'operating_system' = ($Record.CustomVariable | Where-Object Name -EQ 'operating_system').Value + 'target_platform' = ($Record.CustomVariable | Where-Object Name -EQ 'target_platform').Value + 'processors' = ($Record.CustomVariable | Where-Object Name -EQ 'processors').Value + 'memory_gb' = ($Record.CustomVariable | Where-Object Name -EQ 'memory_gb').Value + 'cidr_block' = ($Record.CustomVariable | Where-Object Name -EQ 'cidr_block').Value + 'data_center' = ($Record.CustomVariable | Where-Object Name -EQ 'data_center').Value + 'licensing_restrictions' = ($Record.CustomVariable | Where-Object Name -EQ 'licensing_restrictions').Value + 'agency_name' = ($Record.CustomVariable | Where-Object Name -EQ 'agency_name').Value + 'application_info' = ($Record.CustomVariable | Where-Object Name -EQ 'application_info').Value + 'support_hours' = ($Record.CustomVariable | Where-Object Name -EQ 'support_hours').Value + 'dr_protection' = ($Record.CustomVariable | Where-Object Name -EQ 'dr_protection').Value + 'startup_priority' = ($Record.CustomVariable | Where-Object Name -EQ 'startup_priority').Value + 'disk_1_os' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_1_os').Value + 'disk_2_swap_disk' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_2_swap_disk').Value + 'disk_3' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_3').Value + 'disk_4' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_4').Value + 'disk_5' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_5').Value + 'disk_6' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_6').Value + 'disk_7' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_7').Value + 'disk_8' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_8').Value + 'disk_9' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_9').Value + 'disk_10' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_10').Value + 'disk_11' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_11').Value + 'disk_12' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_12').Value + 'disk_13' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_13').Value + 'disk_14' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_14').Value + 'disk_15' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_15').Value + 'disk_16' = ($Record.CustomVariable | Where-Object Name -EQ 'disk_16').Value + } + + ForEach ($Property in $Record.PSObject.Properties) { + If ($obj.PSObject.Properties.Name -match $Property.Name) { + #Write-Verbose -Message ("Property " + $Property.Name + " already in obj") + } + Else { + # add missing default RITM property to new obj + $obj | Add-Member -MemberType $Property.MemberType -Name $Property.Name -Value $Property.Value -TypeName $Property.TypeNameOfValue -Verbose + } + } + ForEach ($Property in $Record.CustomVariable) { + If ($obj.PSObject.Properties.Name -match $Property.Name) { + #Write-Verbose -Message ("Property " + $Property.Name + " already in obj") + } + Else { + # add missing custom variables to new obj + $obj | Add-Member -MemberType NoteProperty -Name $Property.Name -Value $Property.Value + } + } + $null = $RecordsToExport.Add($obj) + If ($RecordsToExport) { $RecordsToExport | Export-Csv $CsvPath -Append -NoTypeInformation -Force } + } + } +} + +#> \ No newline at end of file diff --git a/Set-CohesityServiceSQL.ps1 b/Set-CohesityServiceSQL.ps1 new file mode 100644 index 0000000..2116129 --- /dev/null +++ b/Set-CohesityServiceSQL.ps1 @@ -0,0 +1,21 @@ +#Add to Local Security Policy +function Add-ServiceLogonRight([string] $Username) { + Write-Host "Enable ServiceLogonRight for $Username" + + $tmp = New-TemporaryFile + secedit /export /cfg "$tmp.inf" | Out-Null + (Get-Content -Encoding ascii "$tmp.inf") -replace '^SeServiceLogonRight .+', "`$0,$Username" | sc -Encoding ascii "$tmp.inf" + secedit /import /cfg "$tmp.inf" /db "$tmp.sdb" | Out-Null + secedit /configure /db "$tmp.sdb" /cfg "$tmp.inf" | Out-Null + Remove-Item $tmp* -ea 0 +} + +Add-ServiceLogonRight -Username svccohesitysql + +# Set Service to Run as Service Account +Stop-Service -Name CohesityAgent +sc.exe config "CohesityAgent" obj="NDGOV\svccohesitysql" password="radiant-yx8aHMrGtc" +Start-Service -Name CohesityAgent + +# Add to Local Administrators group +Add-LocalGroupMember -Group Administrators -Member "ndgov\svccohesitysql" \ No newline at end of file diff --git a/Set-ESULicensing.ps1 b/Set-ESULicensing.ps1 new file mode 100644 index 0000000..10be74e --- /dev/null +++ b/Set-ESULicensing.ps1 @@ -0,0 +1,18 @@ +#remediate +Invoke-Command -Scriptblock { + cscript C:\Windows\System32\slmgr.vbs -upk + cscript C:\Windows\System32\slmgr.vbs -ipk MMFTT-7FBRY-W9QYW-37FMB-TRPJK + cscript C:\Windows\System32\slmgr.vbs -ato 553673ed-6ddf-419c-a153-b760283472fd +} + +# Discovery +$Compliant = $false +$ActivationString = Invoke-Command -Scriptblock { cscript C:\Windows\System32\slmgr.vbs -xpr } -Session $x +If ($ActivationString -like "Windows(R) 7, Server-ESU-Year1 edition*" -and $ActivationString -like "*The machine is permanently activated.*") { + $Compliant = $true +} +else { + $Compliant = $false +} + +$Compliant \ No newline at end of file diff --git a/SpotifyDownloader.ps1 b/SpotifyDownloader.ps1 new file mode 100644 index 0000000..4307e75 --- /dev/null +++ b/SpotifyDownloader.ps1 @@ -0,0 +1,20 @@ +<# + Requirements: + Needs SpotDL python project installed +#> + +New-Item -Path "D:\" -Name ("spotdl_" + (Get-Date -UFormat "%y%m%d")) -ItemType Directory +$RootUrl = "https://xmplaylist.com/api/station/thehighway/most-heard" +$DaysToReview = @(7, 30, 60) + +ForEach ($subdays in $DaysToReview) { + #write-warning ($url + "?subdays=" + $subdays) + $result += Invoke-RestMethod -Uri ($RootUrl + "?subDays=" + $subdays) -Method Get -ContentType "application/json" +} + +$UniqueTracks = ($Result | Select -Unique id).Id + +ForEach ($Id in $UniqueTracks) { + $Url = (($Result | Where-Object Id -eq $Id | Select -First 1).links | where-object site -eq spotify | select -first 1).url + Invoke-Expression -Command ("spotdl " + $Url) +} \ No newline at end of file diff --git a/TranscriptData.ps1 b/TranscriptData.ps1 new file mode 100644 index 0000000..a60110a --- /dev/null +++ b/TranscriptData.ps1 @@ -0,0 +1,58 @@ +$transcript = Get-Content D:\Downloads\transcript.txt + +$RawResult = [System.Collections.ArrayList]@() + +$x = 0 + +While ($x -lt (@($transcript).count)) { + + $obj = [pscustomobject]@{ + timestamp = $transcript[$x + 0] + speaker = $transcript[$x + 1] + words = $transcript[$x + 2] + } + + $null = $RawResult.Add($obj) + $x = $x + 3 +} + +$WordsResult = [System.Collections.ArrayList]@() +ForEach ($dialog in $RawResult) { + ForEach ($word in $dialog.words.split(' ')) { + $word = [regex]::Replace($word, "[^a-zA-Z0-9\s]", "") + $obj = [pscustomobject]@{ + timestamp = $dialog.timestamp + speaker = $dialog.speaker + word = $word + } + $null = $WordsResult.Add($obj) + } +} + + +# Top 300 Words +$WordsResult | Group-Object Word | Sort-Object -Descending Count | select -First 300 + +# Top words by speaker +$WordsBySpeakerResult = [System.Collections.ArrayList]@() +$DialogBySpeaker = $WordsResult | Group-Object speaker +ForEach ($speaker in $DialogBySpeaker) { + $Top10SpeakerWords = $speaker.Group | Group-Object Word | Sort-Object -Descending Count | select -First 10 + $obj = [pscustomobject]@{ + speaker = $speaker.name + word1 = $Top10SpeakerWords[0].Name + word2 = $Top10SpeakerWords[1].Name + word3 = $Top10SpeakerWords[2].Name + word4 = $Top10SpeakerWords[3].Name + word5 = $Top10SpeakerWords[4].Name + word6 = $Top10SpeakerWords[5].Name + word7 = $Top10SpeakerWords[6].Name + word8 = $Top10SpeakerWords[7].Name + word9 = $Top10SpeakerWords[8].Name + word10 = $Top10SpeakerWords[9].Name + } + $null = $WordsBySpeakerResult.Add($obj) +} + +$TopNouns = (Import-Csv "D:\Downloads\english-word-list-nouns.csv" -Delimiter ';').word +$FilteredWordsResult = $WordsResult \ No newline at end of file diff --git a/VM-AddToSolarwinds.ps1 b/VM-AddToSolarwinds.ps1 new file mode 100644 index 0000000..c302e95 --- /dev/null +++ b/VM-AddToSolarwinds.ps1 @@ -0,0 +1,14 @@ +$Func = { + param($C) + Import-SWDiscovery -ComputerName $C -Integration ServiceNow +} +Invoke-Command -ComputerName itdslrwndstst2.nd.gov -ScriptBlock $Func -ArgumentList $FQDN -Credential $SwCred + + + + +$Func = { + param($c) + Import-SWDiscovery -ComputerName $c -Integration ServiceNow +} +Invoke-Command -ComputerName itdslrwnds.nd.gov -ScriptBlock $Func -ArgumentList itdcndstfc19.nd.gov -Credential $IaaSAuto #Cred \ No newline at end of file diff --git a/VMware-2403_coolingprep.ps1 b/VMware-2403_coolingprep.ps1 new file mode 100644 index 0000000..0388315 --- /dev/null +++ b/VMware-2403_coolingprep.ps1 @@ -0,0 +1,74 @@ +# shutdown VDI via GUI + +# Get All VMs 5 minutes +$AllVMs = Get-Datacenter -Name Primary* | Get-Cluster | Where-Object Name -ne MGMT1 | Get-VM +$AllVMTags = $AllVMs | Get-TagAssignment -Category DTAP, StartupPriority # 3.5 minutes + +# while that runs, vmotion des-cad rabbitmq ??? contact Shawn F for Solarwinds + +<# retag VMware VMs to Priority 0 +get-vm -name itdvm* | Get-TagAssignment -Category StartupPriority | Remove-TagAssignment -Confirm:$false +$Tag = Get-Tag -Category StartupPriority -Name 0 -Server itdvmvc1.nd.gov +get-vm -name itdvm* | Get-TagAssignment -Category StartupPriority | Remove-TagAssignment -Confirm:$false + +Get-VM -name itdvm* | ForEach-Object{ + $ViServer=$_.Uid.split('@')[1].split(':')[0] + $Tag = Get-Tag -Category StartupPriority -Name 0 -Server $ViServer + $_ | New-TagAssignment -Tag $Tag +} +#> + +$AllVMsWithTags = [System.Collections.ArrayList]@() + +ForEach ($VM in $AllVMs) { + $obj = [PSCustomObject]@{ + 'VMName' = $VM.Name; + 'DTAP' = ($AllVMTags | Where-Object { $_.Entity.Name -eq $VM.Name -and $_.Tag.Category.Name -eq 'DTAP' }).Tag.Name + 'StartupPriority' = ($AllVMTags | Where-Object { $_.Entity.Name -eq $VM.Name -and $_.Tag.Category.Name -eq 'StartupPriority' }).Tag.Name + } + + #Write-Output $obj + $null = $AllVMsWithTags.Add($obj) +} + +#Populate variables +$AllTest5 = $AllVMsWithTags | Where-Object {$_.StartupPriority -eq 5 -and $_.DTAP -eq 'Test'} +$AllTest4 = $AllVMsWithTags | Where-Object {$_.StartupPriority -eq 4 -and $_.DTAP -eq 'Test'} +$AllTest3 = $AllVMsWithTags | Where-Object {$_.StartupPriority -eq 3 -and $_.DTAP -eq 'Test'} +$AllTest2 = $AllVMsWithTags | Where-Object {$_.StartupPriority -eq 2 -and $_.DTAP -eq 'Test'} +$AllTest1 = $AllVMsWithTags | Where-Object {$_.StartupPriority -eq 1 -and $_.DTAP -eq 'Test'} + +<# +$AllProd5 = $AllVMsWithTags | Where-Object {$_.StartupPriority -eq 5 -and $_.DTAP -eq 'Production'} +$AllProd4 = $AllVMsWithTags | Where-Object {$_.StartupPriority -eq 4 -and $_.DTAP -eq 'Production'} +$AllProd3 = $AllVMsWithTags | Where-Object {$_.StartupPriority -eq 3 -and $_.DTAP -eq 'Production'} +$AllProd2 = $AllVMsWithTags | Where-Object {$_.StartupPriority -eq 2 -and $_.DTAP -eq 'Production'} +$AllProd1 = $AllVMsWithTags | Where-Object {$_.StartupPriority -eq 1 -and $_.DTAP -eq 'Production'} +#> + +# shutdown VMs by variable group +ForEach($VM in $AllTest5){ + Get-VM -Name $VM.VMName -Server itdvmvc1.nd.gov #|Stop-VMGuest +} + +# monitor the shutdown +Get-Datacenter -Name Primary* | Get-VM -Name $AllTest5.VMName + + + + + +# disable all host alarms and put all hosts into maintenance +$AllVMHosts = Get-Datacenter -Name Primary* | Get-Cluster | Where-Object Name -ne MGMT1 | Get-VMHost +foreach ($VMHostName in $AllVMHosts) { + Write-Warning -Message ("Start $VMHostName") + $GetVMHost = Get-VMHost $VMHostName + $VIServer = $GetVMHost.Uid.Split('@')[1].Split(':')[0] + $alarmMgr = Get-View AlarmManager -Server $VIServer + $alarmEnabled = $GetVMHost.ExtensionData.AlarmActionsEnabled + if ($alarmEnabled -eq $true) { + $alarmMgr.EnableAlarmActions($GetVMHost.ExtensionData.MoRef, $false) + } +} +# maintenance manually in GUI ******************************* +# shutdown manually in GUI ******************************* \ No newline at end of file diff --git a/VMware-AutoBuildLoop.ps1 b/VMware-AutoBuildLoop.ps1 new file mode 100644 index 0000000..ec1533c --- /dev/null +++ b/VMware-AutoBuildLoop.ps1 @@ -0,0 +1,960 @@ +# looper +<# + + +#> + +$FQDNs = @" +itdpszeeland1.nd.gov +"@ + +$FQDNs = ConvertTo-Array -MultiLineString $FQDNs + +ForEach ($FQDN in $FQDNs) { + Write-Warning "[$FQDN]:Start" + $SPCred = $StdCred + $ADCred = $PrvCred + $PSCred = $PrvCred + $VMCred = $PrvCred + $CcmCred = $PrvCred + #> + <# Get Credentials + + $SPCred = Get-AutomationPSCredential -Name 'SharePoint IaaS ReadWrite' + $ADCred = Get-AutomationPSCredential -Name 'ITD IaaS Automation' + $PSCred = Get-AutomationPSCredential -Name 'ITD IaaS Automation' + $IBCred = New-Object System.Management.Automation.PSCredential ($PSCred.UserName.split('\')[1], $ADCred.Password) + $VMCred = Get-AutomationPSCredential -Name 'VMware Auto' + $CcmCred = Get-AutomationPSCredential -Name 'ITD IaaS Automation'#> + #> + Clear-DnsClientCache + $SharePointList = Get-ITDVMwareSharePointVMGuestList -Credential $SPCred + Write-Warning ("SPList count: " + $SharePointList.count) + $SPItem = $SharePointList | Where-Object Title -EQ $FQDN + If ($null -eq $SPItem.Cluster) { + Write-Error "VMware Cluster not specified in SharePoint" + Stop + } + Write-Warning $SPItem + $HostName = $FQDN.split('.')[0] + + # Infoblox + [Net.IpAddress]$NetworkId = $SPItem.CIDR.split('/')[0] + [Net.IPAddress]$IpAddress = (Resolve-DnsName -Name $FQDN -ErrorAction SilentlyContinue).IPAddress + $SubnetMaskInt = $SPItem.Cidr.split('/')[1] + $Int64 = ([convert]::ToInt64(('1' * $SubnetMaskInt + '0' * (32 - $SubnetMaskInt)), 2)) + [Net.IPAddress]$SubnetMask = '{0}.{1}.{2}.{3}' -f ([math]::Truncate($Int64 / 16777216)).ToString(), + ([math]::Truncate(($Int64 % 16777216) / 65536)).ToString(), + ([math]::Truncate(($Int64 % 65536) / 256)).ToString(), + ([math]::Truncate($Int64 % 256)).ToString() + $IPSplit = $SPItem.Cidr.Split('.') + [Net.IPAddress]$DefaultGateway = ($IPSplit[0] + '.' + $IPSplit[1] + '.' + $IPSplit[2] + '.' + (($SPItem.Cidr.split('/')[0].split('.')[-1] -as [int]) + 1) ) + <# + If (($IpAddress.Address -band $SubnetMask.Address) -eq ($NetworkId.Address -band $SubnetMask.Address)) { + Write-Verbose "IP Address and CIDR Block match" + } + Else { + Write-Error "DNS record already exists, and does not match CIDR Block" -ErrorAction Stop + } + #> + + If ($IpAddress) { + If (($IpAddress.Address -band $SubnetMask.Address) -eq ($NetworkId.Address -band $SubnetMask.Address)) { + Write-Warning "DNS record already exists, CIDR Block match" + } + else { + Write-Error "DNS record already exists, and does not match CIDR Block" + Break + } + } + Else { + New-ITDIbDNSRecordNextAvailableIP -Hostname $SPItem.Title -CIDR $SPItem.CIDR -Credential $RadiusCred + [Net.IPAddress]$IpAddress = (Resolve-DnsName -Name $FQDN -ErrorAction SilentlyContinue).IPAddress + } + #> + If ((Test-NetConnection -ComputerName $IpAddress.IPAddressToString).PingSucceeded) { + Write-Error "IP Address already in use." -ErrorAction Stop + } + + # Passwordstate BB before baseline, AB after baseline + If ($FQDN -like "itdcnd*") { + $PasswordStateList = "Peoplesoft Share PW" + } + Else { + $PasswordStateList = "CSRC" + } + $LocalCredential = New-ITDPassword -Title $FQDN -UserName itdadmin -Description 'Local Administrator' -PasswordList $PasswordStateList -Credential $PSCred + $GuestCredentialBB = New-Object System.Management.Automation.PSCredential ('Administrator', ($LocalCredential.Password | ConvertTo-SecureString -AsPlainText -Force)) + $GuestCredentialAB = New-Object System.Management.Automation.PSCredential ($LocalCredential.UserName, ($LocalCredential.Password | ConvertTo-SecureString -AsPlainText -Force)) + $GuestCredential = $GuestCredentialBB + + # VMware + Connect-ITDvCenter -Credential $VMCred + If (Get-VM -Name $FQDN -ErrorAction SilentlyContinue) { + Write-Error "Virtual machine with the name $FQDN already exists." -ErrorAction Stop + Stop + Stop + } + + switch ($SPItem.Cluster) { + "WINDOWS1" { + $ViServer = 'itdvmvc1.nd.gov' + $ComputeCluster = Get-Cluster WINDOWS1 + $VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-Data-Server" + $DiskStorageFormat = 'Thin' + If ($SPItem.LicensingRestrictions -like "*SQL*") { + $DatastoreCluster = Get-DatastoreCluster -Name "WINDOWS1_FS92_SQL" + } + Else { + $DatastoreCluster = Get-DatastoreCluster -Name "WINDOWS1_FS92_Gen" + } + } + "WINDOWS2" { + $ViServer = 'itdvmvc2.nd.gov' + $ComputeCluster = Get-Cluster WINDOWS2 + $VirtualSwitch = Get-VDSwitch -Name "dvSwitch-SDC-Data-Server" + $DiskStorageFormat = 'Thin' + If ($SPItem.LicensingRestrictions -like "*SQL*") { + $DatastoreCluster = Get-DatastoreCluster -Name "WINDOWS2_FS92_SQL" + } + Else { + $DatastoreCluster = Get-DatastoreCluster -Name "WINDOWS2_FS92_Gen" + } + } + "SQL1" { + $ViServer = 'itdvmvc1.nd.gov' + $ComputeCluster = Get-Cluster SQL1 + $VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-Data-Server" + $DiskStorageFormat = 'EagerZeroedThick' + $DatastoreCluster = Get-DatastoreCluster -Name "SQL1_FS92_Gen" + } + "SQL2" { + $ViServer = 'itdvmvc2.nd.gov' + $ComputeCluster = Get-Cluster SQL2 + $VirtualSwitch = Get-VDSwitch -Name "dvSwitch-SDC-Data-Server" + $DiskStorageFormat = 'EagerZeroedThick' + $DatastoreCluster = Get-DatastoreCluster -Name "SQL2_FS92_Gen" + } + "WAS1" { + $ViServer = 'itdvmvc1.nd.gov' + $ComputeCluster = Get-Cluster WAS1 + $VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-Data-Server" + $DiskStorageFormat = 'Thin' + $DatastoreCluster = Get-DatastoreCluster -Name "WAS1_FS92_Gen" + } + "WAS2" { + $ViServer = 'itdvmvc2.nd.gov' + $ComputeCluster = Get-Cluster WAS2 + $VirtualSwitch = Get-VDSwitch -Name "dvSwitch-SDC-Data-Server" + $DiskStorageFormat = 'Thin' + $DatastoreCluster = Get-DatastoreCluster -Name "WAS2_FS92_Gen" + } + "PS1" { + $ViServer = 'itdvmvc1.nd.gov' + $ComputeCluster = Get-Cluster PS1 + $VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-Data-Server" + $DiskStorageFormat = 'Thin' + $DatastoreCluster = Get-DatastoreCluster -Name "PS1_FS92_Gen" + } + "PS2" { + $ViServer = 'itdvmvc2.nd.gov' + $ComputeCluster = Get-Cluster PS2 + $VirtualSwitch = Get-VDSwitch -Name "dvSwitch-SDC-Data-Server" + $DiskStorageFormat = 'Thin' + $DatastoreCluster = Get-DatastoreCluster -Name "PS2_FS92_Gen" + } + "TEL1" { + $ViServer = 'itdvmvc1.nd.gov' + $ComputeCluster = Get-Cluster TEL1 + $VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-TEL1-Data" + $DiskStorageFormat = 'Thin' + $DatastoreCluster = Get-DatastoreCluster -Name "TEL1_FS92_Gen" + } + "TEL2" { + $ViServer = 'itdvmvc2.nd.gov' + $ComputeCluster = Get-Cluster TEL2 + $VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-TEL2-Data" + $DiskStorageFormat = 'Thin' + $DatastoreCluster = Get-DatastoreCluster -Name "TEL2_FS92_Gen" + } + Default { + Write-Error "Cluster not found" -ErrorAction Stop + } + <# + "DCN1" { + $ViServer = 'itdvmvc1.nd.gov' + $VirtualSwitch = Get-VDSwitch -Name "dvSwitch-DCN-vMotion-Data" + $DiskStorageFormat = 'Thin' + } + #> + } + + # verify disk will fit + + $DiskTotal = $SPItem.Disk1 + $SPItem.Disk2 + $SPItem.Disk3 + If ($DatastoreCluster) { + } + Else { + $DatastoreCluster = Get-DatastoreCluster | Where-Object Name -Like ("*" + $SPItem.Cluster + "*") + } + $ClusterDatastoreWithHighestFreeSpaceGB = ($DatastoreCluster | Get-Datastore | Sort-Object FreeSpaceGB -Descending | Select-Object -First 1) + If ($ClusterDatastoreWithHighestFreeSpaceGB.FreeSpaceGB -gt $DiskTotal) { + Write-Warning ("VM DiskTotal " + $DiskTotal + "GB, will fit on " + $ClusterDatastoreWithHighestFreeSpaceGB.Name + " (" + [math]::round($ClusterDatastoreWithHighestFreeSpaceGB.FreeSpaceGB, 0) + "GB free)") + } + else { + Write-Warning ("VM DiskTotal " + $DiskTotal + "GB, will not fit on " + $ClusterDatastoreWithHighestFreeSpaceGB.Name + " (" + [math]::round($ClusterDatastoreWithHighestFreeSpaceGB.FreeSpaceGB, 0) + "GB free)") + Write-Error ("New VM " + $FQDN + " needs " + $DiskTotal + "GB of free space on a single datastore in the " + $DatastoreCluster.Name + " datastore cluster.") -ErrorAction Stop + } + + $FolderLocation = $ComputeCluster | Get-Datacenter | Get-Folder -Name "_New Builds" + + switch ($SPItem.OS) { + "Windows Server 2012R2 Standard (64-Bit)" { $Template = "Windows Server 2012R2 Standard" } + "Windows Server 2016 Standard (64-Bit)" { $Template = "Windows Server 2016 Standard" } + "Windows Server 2019 Standard (64-Bit)" { $Template = "Windows Server 2019 Standard" } + "Windows Server 2019 Datacenter (64-Bit)" { $Template = "Windows Server 2019 Standard" } + Default {Write-Error "Invalid template" -ErrorAction Stop} + } + + $PortGroupsAvailable = Get-VDPortgroup -Server $ViServer -VDSwitch $VirtualSwitch + $PortGroup = $PortGroupsAvailable | Where-Object Name -Like ("dvPG_" + $SPItem.Vlan_Id + "*") + If (!($PortGroup)) { + Write-Error "Virtual port group not found" -ErrorAction Stop + Stop + } + If (@($PortGroup).count -gt 1) { + Write-Error "Multiple port groups found" -ErrorAction Stop + Stop + } + + $NewOSSpecName = ("AutoBuild-$Hostname-" + (Get-Date -UFormat "%Y%m%d%H%M%S")) + Write-Warning "NewOSSpecName = $NewOSSpecName" + Get-OSCustomizationSpec -Name "Windows (Auto)" -Server $ViServer | New-OSCustomizationSpec -Name $NewOSSpecName -Type Persistent -Server $ViServer + + Get-OSCustomizationSpec -Name $NewOSSpecName -Server $ViServer | ` + Set-OSCustomizationSpec ` + -NamingScheme fixed ` + -NamingPrefix $Hostname ` + -AdminPassword $GuestCredentialBB.GetNetworkCredential().Password + + Get-OSCustomizationSpec -Name $NewOSSpecName -Server $ViServer | ` + Get-OSCustomizationNicMapping | ` + Set-OSCustomizationNicMapping ` + -IpMode UseStaticIP ` + -IpAddress $IpAddress.IPAddressToString ` + -SubnetMask $SubnetMask.IPAddressToString ` + -DefaultGateway $DefaultGateway.IPAddressToString ` + -Dns "10.2.7.40", "10.10.10.10" + + $OSSpec = Get-OSCustomizationSpec -Name $NewOSSpecName -Server $ViServer + <# + $NewVMParams = @{ + Name = $FQDN; + ResourcePool = $SPItem.Cluster; + Datastore = $DatastoreCluster; + DiskStorageFormat = $DiskStorageFormat; + Template = $Template; + Location = $FolderLocation; + OSCustomizationSpec = $OSSpec; + } + $NewVMParams + + New-VM @NewVMParams + #> + + #Set-Location C:\Temp # required to make New-VM work, https://communities.vmware.com/thread/591294 + # seems fixed on 2022/07/01 + try { + Write-Warning $FQDN + Write-Warning $ComputeCluster.Name + Write-Warning $DatastoreCluster + Write-Warning $DiskStorageFormat + Write-Warning $Template + Write-Warning $FolderLocation + Write-Warning $OSSpec + New-VM -Name $FQDN -ResourcePool $ComputeCluster.Name -Datastore $DatastoreCluster -DiskStorageFormat $DiskStorageFormat -Template $Template -Location $FolderLocation -OSCustomizationSpec $OSSpec + } + catch { + Stop + Stop + } + + #If (!($BuildError)) { + $VM = Get-VM -Name $FQDN + + # Ensure CPU/Memory Hot-Add Enabled + $vmView = $VM | Get-View + $vmConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec + $vmOptValCPU = New-Object VMware.Vim.OptionValue + $vmOptValMem = New-Object VMware.Vim.OptionValue + $vmOptValCPU.Key = "vcpu.hotadd" + $vmOptValMem.Key = "mem.hotadd" + $vmOptValCPU.Value = "true" + $vmOptValMem.Value = "true" + $vmConfigSpec.ExtraConfig += $vmOptValCPU + $vmConfigSpec.ExtraConfig += $vmOptValMem + $vmView.ReconfigVM($vmConfigSpec) + + # Set CPU, Memory, Network + $VM | Set-VM -NumCpu $SPItem.Processors -MemoryGB $SPItem.RAM -Confirm:$false + $VM | Get-NetworkAdapter | Set-NetworkAdapter -Portgroup $PortGroup -Confirm:$false + + # Power On VM + $VM | Start-VM + + # Wait for Customization to finish + $VMStarted = $false + $VMCustomizationStarted = $false + $VMCustomizationResult = $false + + While ($VMStarted -eq $false -or $VMCustomizationStarted -eq $false -or $VMCustomizationResult -eq $false) { + Write-Warning ("Customization wait loop started " + (Get-Date)) + Write-Verbose "Current Status:" + Write-Verbose ("VMStarted: " + $VMStarted) + Write-Verbose ("VMCustomizationStarted: " + $VMCustomizationStarted) + Write-Verbose ("VMCustomizationResult: " + $VMCustomizationResult) + $GetVIEventRuntime = Measure-Command -Expression { $VMEvents = Get-VIEvent -Entity $VM -Server $ViServer -ErrorAction SilentlyContinue } + Write-Verbose ("Get-VIEvent last run time: " + $GetVIEventRuntime.TotalSeconds + " seconds") + If ($VMStarted -eq $false) { + If (@($VMEvents | Where-Object { $_.GetType().Name -eq "VMStartingEvent" })) { + $VMStarted = $true + Write-Warning "[$FQDN]:Virtual machine started" + } + } + If ($VMCustomizationStarted -eq $false) { + If (@($VMEvents | Where-Object { $_.GetType().Name -eq "CustomizationStartedEvent" })) { + $VMCustomizationStarted = $true + Write-Warning "[$FQDN]:Virtual machine customization started" + } + } + If ($VMCustomizationResult -eq $false) { + If (@($VMEvents | Where-Object { $_.GetType().Name -eq "CustomizationFailed" })) { + $VMCustomizationResult = $true + Write-Error "[$FQDN]:Virtual machine customization failed" + Exit + Exit + } + If (@($VMEvents | Where-Object { $_.GetType().Name -eq "CustomizationSucceeded" })) { + $VMCustomizationResult = $true + Write-Warning "[$FQDN]:Virtual machine customization completed" + } + } + } + + # Delete OS Customization Spec + # Get-OSCustomizationSpec -Name $NewOSSpecName | Remove-OSCustomizationSpec -Confirm:$false + + # Add/Expand Disks + Write-Warning -Message "[$FQDN]:Modify disks 1,2,3" + $VMDisk = $VM | Get-HardDisk + $VMDisk1 = $VMDisk | Where-Object Name -EQ "Hard disk 1" + $VMDisk2 = $VMDisk | Where-Object Name -EQ "Hard disk 2" + $VMDisk3 = $VMDisk | Where-Object Name -EQ "Hard disk 3" + + If ($SPItem.Disk1) { + If (!$VMDisk1) { + $VM | New-HardDisk ` + -CapacityGB $SPItem.Disk1 ` + -StorageFormat Thin ` + -DiskType Flat ` + -Persistence Persistent + } + $VMDisk1 = $VM | Get-HardDisk | Where-Object Name -EQ "Hard disk 1" + If ($VMDisk1.CapacityGB -lt $SPItem.Disk1) { + Set-HardDisk -HardDisk $VMDisk1 -CapacityGB $SPItem.Disk1 -Confirm:$false + } + } + + If ($SPItem.Disk2) { + If (!$VMDisk2) { + $VM | New-HardDisk ` + -CapacityGB $SPItem.Disk2 ` + -StorageFormat Thin ` + -DiskType Flat ` + -Persistence Persistent + } + $VMDisk2 = $VM | Get-HardDisk | Where-Object Name -EQ "Hard disk 2" + If ($VMDisk2.CapacityGB -lt $SPItem.Disk2) { + Set-HardDisk -HardDisk $VMDisk2 -CapacityGB $SPItem.Disk2 -Confirm:$false + } + } + + If ($SPItem.Disk3) { + If (!$VMDisk3) { + $VM | New-HardDisk ` + -CapacityGB $SPItem.Disk3 ` + -StorageFormat Thin ` + -DiskType Flat ` + -Persistence Persistent + } + $VMDisk3 = $VM | Get-HardDisk | Where-Object Name -EQ "Hard disk 3" + If ($VMDisk3.CapacityGB -lt $SPItem.Disk3) { + Set-HardDisk -HardDisk $VMDisk3 -CapacityGB $SPItem.Disk3 -Confirm:$false + } + } + + # skipping tag assignment for now + # Set-ITDVMwareVMTagFromSharePoint -ComputerName $FQDN -SharePointCredential $SPCred -Verbose + + # Run Guest OS code + # Enable RDP with NLA - can be done with GPO + # Enable WinRM - ITD WinRM enable + # Configure Power Plan - ITD-PowerPlan-HighPerformance + # Activate Windows, KMS on-premise, Azure to Azure + # DVD Drive to Z: + # Expand C: + # Partition/Format the rest, GPT/NTFS + # Configure Page File Disk + # Enabling server manager performance monitors + # Configure Time Zone and NTP - no GPO available + # Disable Windows Firewall + # Join AD + + #Initialize-ITDServer -Credential $ADCred + + + Write-Warning -Message "[$FQDN]:Assigning WMI Tag 000-Prod, SCCM will change it later if required" + Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredential -ScriptType PowerShell -ScriptText { + # Move DVD Drive Mount + try { + Write-Verbose "Create new Class" + $Class = New-Object System.Management.ManagementClass("root\cimv2", [String]::Empty, $null); + + $Class["__CLASS"] = "ITD"; + $Class.Qualifiers.Add("Static", $true) + $Class.Properties.Add("MyKey", [System.Management.CimType]::String, $false) + $Class.Properties["MyKey"].Qualifiers.Add("Key", $true) + + $Class.Properties.Add("LastModified", [System.Management.CimType]::String, $false) + $Class.Properties.Add("DTAP", [System.Management.CimType]::String, $false) + $Class.Properties.Add("Baseline", [System.Management.CimType]::String, $false) + + $Class.Put() + + Write-Verbose "Create single ITD Object" + Set-WmiInstance -Class ITD -Arguments @{LastModified = (Get-Date); DTAP = "Prod"; Baseline = "000" } + } + catch { + Throw $_ + Break + } + } + + Write-Warning -Message "[$FQDN]:Checking for DVD drive..." + Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredential -ScriptType PowerShell -ScriptText { + # Move DVD Drive Mount + try { + $dvd_letter = 'Z' + $dvd = Get-WmiObject -Class Win32_Volume -Filter "DriveType=5" | Select-Object -First 1 + if ($dvd.Name -notmatch $dvd_letter) { + Write-Verbose -Message "Found DVD drive, switching to $dvd_letter`:" + + Set-WmiInstance -InputObject $dvd -Arguments @{DriveLetter = "$dvd_letter`:" } | Out-Null + + Write-Verbose -Message "DVD drive moved to drive letter $dvd_letter`:" + } + else { + Write-Verbose -Message "No DVD drive changes required, continuing..." + } + } + catch { + Throw $_ + Break + } + } + + Write-Warning -Message "[$FQDN]:Checking for unpartitioned space on C: disk..." + Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredential -ScriptType PowerShell -ScriptText { + # Expand C: Partition To Maximum Extent + + + try { + $cSize = ( Get-Partition -DriveLetter C ).Size + $cMaxSize = ( Get-PartitionSupportedSize -DriveLetter C ).SizeMax + + if ($cSize -lt $cMaxSize) { + Write-Verbose -Message "Expanding C: from $($csize / 1GB)GB to $($cMaxSize / 1GB)GB..." + + Resize-Partition -DriveLetter C -Size $cMaxSize + + Write-Verbose -Message "C: expanded to $($cMaxSize / 1GB)GB." + } + else { + Write-Verbose -Message "C: is already at maximum size, continuing..." + } + } + catch { + Throw $_ + Break + } + } + + Write-Warning "[$FQDN]:Start Extra Disk(s) config" + Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredential -ScriptType PowerShell -ScriptText { + # Initialize Additional Disks + try { + # Non-initialized and MBR-initialized disks will have 0 partitions by default, but GPT-initialized disks will have 1 system reserved partition by default + $disks = Get-Disk | Where-Object { $_.NumberOfPartitions -eq 0 -or ( $_.PartitionStyle -eq 'GPT' -and $_.NumberOfPartitions -eq 1 ) } | Sort-Object -Property Number + + if ($disks) { + Write-Verbose -Message "Found $(@($disks).Count) unpartitioned disks." + + # Prevent the "You must format this partition before using it." popup + if (Get-Service ShellHWDetection -ErrorAction SilentlyContinue) { Stop-Service ShellHWDetection -ErrorAction SilentlyContinue } + + foreach ($disk in $disks) { + if ($disk.IsOffline) { + Set-Disk $disk.Number -IsOffline $false + Write-Verbose -Message "Brought disk $($disk.Number)($("{0:n0}GB" -f ($disk.Size / 1GB))) online..." + } + + if ($disk.IsReadOnly) { Set-Disk $disk.Number -IsReadOnly $false } + if ($disk.PartitionStyle -eq 'RAW') { Initialize-Disk $disk.Number -PartitionStyle GPT -ErrorAction SilentlyContinue } + + $diskParam = @{ + FileSystem = 'NTFS' + Confirm = $false + } + + $driveLetter = [Int][Char]'D' + while (Get-Volume -DriveLetter $([Char]$driveLetter) -ErrorAction SilentlyContinue) { + $driveLetter++ + } + + $diskParam.DriveLetter = [Char]$driveLetter + + if (@($disks).IndexOf($disk) -eq 0 -and (-not (Get-Volume -DriveLetter D -ErrorAction SilentlyContinue))) { + $diskParam.NewFileSystemLabel = 'Temporary Storage' + } + elseif (@($disks).IndexOf($disk) -eq 1 -and (-not (Get-Volume -DriveLetter E -ErrorAction SilentlyContinue))) { + $diskParam.NewFileSystemLabel = 'Data' + } + + [void](New-Partition -DiskNumber $disk.Number -DriveLetter $diskParam.DriveLetter -UseMaximumSize) + [void](Format-Volume @diskParam) + } + } + else { + Write-Verbose -Message "No unpartitioned disks found, continuing..." + } + } + catch { + Throw $_ + Break + } + finally { + if (Get-Service ShellHWDetection -ErrorAction SilentlyContinue) { Start-Service ShellHWDetection -ErrorAction SilentlyContinue } + } + } + + Write-Warning "[$FQDN]:Start Page File Configuration" + Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredential -ScriptType PowerShell -ScriptText { + # Configure Page File + if (Get-Partition -DriveLetter D -ErrorAction SilentlyContinue) { + Write-Verbose -Message "Setting up pagefile.sys on D:..." + + try { + if (-not [IO.File]::Exists('D:\pagefile.sys')) { + $autoPage = Get-WmiObject -Class Win32_ComputerSystem -EnableAllPrivileges + $autoPage.AutomaticManagedPagefile = $false + [void]$autoPage.Put() + + Write-Verbose -Message "Disabled automatic pagefile management." + + $pageFile = Get-WmiObject -Class Win32_PageFileSetting -EnableAllPrivileges + $pageFile.Delete() + + Write-Verbose -Message "Deleted C:\pagefile.sys." + + Set-WmiInstance -Class Win32_PageFileSetting -Arguments @{ Name = "D:\pagefile.sys"; InitialSize = 0; MaximumSize = 0; } -EnableAllPrivileges | Out-Null + + Write-Verbose -Message "System managed page file created on D:\pagefile.sys." + } + else { + Write-Verbose -Message "Pagefile already configured on D:, continuing..." + } + } + catch { + Throw $_ + Break + } + } + else { + Write-Verbose -Message "Page file drive not found, cannot set up page file. Continuing server configuration..." + Write-Warning "Page file drive not found, cannot set up page file. Continuing server configuration..." + } + } + + Write-Warning -Message "[$FQDN]:Enabling Remote Management..." + Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredential -ScriptType PowerShell -ScriptText { + # Configure Remote Management (RDP/PoSH) + try { + Write-Verbose -Message "Checking WinRM..." + + if (Test-WSMan -ErrorAction SilentlyContinue) { + Write-Verbose -Message "WinRM is already enabled." + } + else { + Enable-PSRemoting -Force + + Write-Verbose -Message "WinRM is now enabled." + } + + Write-Verbose -Message "Checking RDP..." + + $RDP = Get-WmiObject Win32_TerminalServiceSetting -Namespace root\cimv2\TerminalServices + $NLA = Get-WmiObject Win32_TSGeneralSetting -Namespace root\cimv2\TerminalServices -Filter "TerminalName='RDP-tcp'" + if ($RDP.AllowTSConnections -eq 0) { + Write-Verbose -Message "RDP is disabled, enabling..." + + $RDP.SetAllowTSConnections(1, 1) | Out-Null + + Write-Verbose -Message "RDP is enabled." + } + else { + Write-Verbose -Message "RDP is already enabled, checking NLA security..." + } + + if ($NLA.UserAuthenticationRequired -eq 0) { + Write-Verbose -Message "RDP is not NLA secured, enabling..." + + $NLA.SetUserAuthenticationRequired(1) | Out-Null + + Write-Verbose -Message "RDP is now NLA secured." + } + else { + Write-Verbose -Message "RDP is already NLA secured." + } + + } + catch { + Throw $_ + Break + } + } + + Write-Warning -Message "[$FQDN]:Checking current power plan..." + Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredential -ScriptType PowerShell -ScriptText { + # Configure Power Plan + try { + $powerPlans = powercfg -l + + if ($powerPlans -match '\*$' -notmatch 'High performance') { + $currentPlan = [regex]::Match($powerPlans, '(?<=(\())[^)]+(?=(\)\s\*))').Value + + Write-Verbose -Message "Power plan is currently set to $currentPlan, changing to High Performance..." + + $highPerformance = [regex]::Match($powerPlans, '([\d\w-\S]+)(?=\s+\(High performance\))').Value + [void](powercfg -setactive $highPerformance) + + Write-Verbose -Message "Power plan set to High Performance." + } + else { + Write-Verbose -Message "Power plan already configured for High Performance." + } + + [void](& w32tm.exe /resync /nowait) + } + catch { + Throw $_ + Break + } + } + + + $TimeSyncFunc = { + # Configure Time/Date Settings + Write-Verbose -Message "Checking current time/date settings..." + $Domain = "" + try { + if ((Get-TimeZone).Id -ne 'Central Standard Time') { + Write-Verbose -Message "Current time zone set to $((Get-TimeZone).Id), setting to Central Standard Time." + + Set-TimeZone -Id 'Central Standard Time' + + Write-Verbose -Message "Time zone set to Central Standard Time." + } + else { + Write-Verbose -Message "Time zone is already set to Central Standard Time." + } + <# + Write-Verbose -Message "Beginning a time synchronization..." + + if ((Get-Service W32Time).Status -eq 'Stopped') { + Start-Service W32Time + } + + [void](& w32tm.exe /config /manualpeerlist:$Domain /syncfromflags:all /update) + + [void](& w32tm.exe /resync /nowait) + + # Start background job to check time service + $tmJob = Start-Job -Name 'ManualTimeSync' -ScriptBlock { + do { + $tmOut = & w32tm.exe /query /status /verbose + + Start-Sleep -Seconds 10 + } until($tmOut -match '^Last Sync Error: 0\D+$') + } + + # If after three minutes time still has not synched, move on. This usually causes no problems. + if ((Wait-Job -Job $tmJob -Timeout 180).State -eq 'Completed') { + Write-Warning -Message "Time synchronization with $($Domain.ToLower()) successful." + } + else { + [void](Stop-Job -Job $tmJob) + Write-Warning -Message "Time synchronization with $($Domain.ToLower()) failed." + } + #> + } + catch { + Throw $_ + Break + } + } + $TimeSyncScriptBlock = $TimeSyncFunc -replace '', $DomainName + $VM | Invoke-VMScript -GuestCredential $GuestCredential -ScriptType PowerShell -ScriptText $TimeSyncScriptBlock + #> + Write-Warning -Message "[$FQDN]:Enabling the server manager performance monitors..." + Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredential -ScriptType PowerShell -ScriptText { + # Enable Performance Counters + + + try { + if (Get-ScheduledTask -TaskName "Server Manager Performance Monitor" | Where-Object State -NE "Running" -ErrorAction SilentlyContinue) { + Enable-ScheduledTask -TaskPath "\Microsoft\Windows\PLA\" -TaskName "Server Manager Performance Monitor" | Start-ScheduledTask + + Write-Verbose -Message "Performance monitors enabled." + } + else { + Write-Verbose -Message "Performance monitors already enabled, continuing..." + } + } + catch { + Throw $_ + Break + } + } + + Write-Warning -Message "[$FQDN]:Disable Windows Firewall" + Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredential -ScriptType PowerShell -ScriptText { + # Disable Windows Firewall + Write-Verbose -Message "Checking for active Windows Firewall..." + + if ((Get-NetFirewallProfile).Enabled -contains 'True') { + Write-Verbose -Message "Windows Firewall is still enabled, disabling it..." + + Set-NetFirewallProfile -Profile Domain, Public, Private -Enabled False + + Write-Verbose -Message "Windows Firewall disabled." + } + else { + Write-Verbose -Message "Windows Firewall already disabled, continuing..." + } + } + + # Active Directory + Write-Warning "[$FQDN]:Join Active Directory (if required)" + $DomainName = $FQDN.Substring($FQDN.IndexOf(".") + 1) + $AppName = $SPItem.AppName + switch ($DomainName) { + 'nd.gov' { + $SearchBaseDomain = "dc=nd,dc=gov" + } + 'ndcloud.gov' { + $SearchBaseDomain = "dc=ndcloud,dc=gov" + } + } + + If ($DomainName -eq "nd.gov") { + $OUAppName = Get-ADOrganizationalUnit -Server $DomainName -SearchBase ("OU=SERVERS,ou=COMPUTERS,ou=ITD," + $SearchBaseDomain) -Filter { Name -eq $AppName } + If (!($OUAppName)) { + $OUAppName = Get-ADOrganizationalUnit -SearchBase ("OU=SERVERS,ou=COMPUTERS,ou=ITD," + $SearchBaseDomain) -Filter { Name -eq 'All-General' } + } + $ExistingADComputer = Get-ADComputer -Filter { Name -eq $Hostname } + If ($ExistingADComputer) { + If ($ExistingADComputer.DistinguishedName -like ("*" + $SPItem.AppName + "*") -or $ExistingADComputer.DistinguishedName -like "*All-General*") { + Write-Warning "AD object already exists, OU path does match" + $OuFinal = $ExistingADComputer.DistinguishedName -replace '^.+?(? -OUPath "" -Credential $DomainJoinCred' + $SecondScriptText = $SecondScriptText -replace '', $DomainName + $SecondScriptText = $SecondScriptText -replace '', $OuFinal + $SecondScriptText = $SecondScriptText -replace '', ("OU=SERVERS,ou=COMPUTERS,ou=ITD," + $SearchBaseDomain) + + Write-Warning -Message "[$FQDN]:Invoke-VMScript to AD join" + $InvokeVMScriptFunc = [System.Management.Automation.ScriptBlock]::Create("$FirstScriptBlock ; $SecondScriptText") + + Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredential -ScriptType PowerShell -ScriptText $InvokeVMScriptFunc + + Write-Warning -Message "[$FQDN]:Restart VMGuest, wait for Tools, then 90 seconds after" + Get-VM -Name $FQDN | Restart-VMGuest -Confirm:$false + Wait-Tools -VM (Get-VM -Name $FQDN) + Start-Sleep -Seconds 90 + } + + Write-Warning ("[$FQDN]:Copying SCCM client installer to C:\temp... " + (Get-Date)) + Copy-VMGuestFile -Source D:\SCCM_Client\ -Destination C:\temp\SCCM_Client -VM (Get-VM -Name $FQDN) -LocalToGuest -GuestCredential $GuestCredentialAB -Force + Write-Warning ("[$FQDN]:SCCM client copy complete " + (Get-Date)) + #E:\AutoBuild\SCCM_Client\ + + # Check if SCCM automatically installed the SCCM client and registered it + $CcmRegistered = $false + $CcmRegistration = Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText { + Get-Content C:\windows\ccm\logs\ClientIDManagerStartup.log + } + If ($CcmRegistration.ScriptOutput -match "Client is registered") { + Write-Warning "Client is registered." + $CcmRegistered = $true + } + ElseIf ($CcmRegistration.ScriptOutput -match "Client is already registered") { + Write-Warning "Client is already registered." + $CcmRegistered = $true + } + If ($CcmRegistered -eq $false) { + Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText { + + If (Get-Process -Name ccmsetup -ErrorAction SilentlyContinue) { + Write-Warning "CCM client is already installing" + $CcmRegistered = $true + } + ElseIf (Get-Process -Name ccmexec -ErrorAction SilentlyContinue) { + Write-Warning "CCM client is already installed" + $CcmRegistered = $true + } + Else { + Write-Warning -Message "Installing SCCM Client..." + Invoke-Expression -Command "C:\temp\SCCM_Client\ccmsetup.exe SMSSITECODE=ITD SMSMP=itdsccmp2.nd.gov DNSSUFFIX=nd.gov" + } + } + } + + Write-Warning "[$FQDN]:Register SCCM Client" + While ($CcmRegistered -eq $false) { + $CcmRegistration = Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText { + Get-Content C:\windows\ccm\logs\ClientIDManagerStartup.log + } + If ($CcmRegistration.ScriptOutput -match "Client is registered") { + Write-Warning "Client is registered." + $CcmRegistered = $true + } + ElseIf ($CcmRegistration.ScriptOutput -match "Client is already registered") { + Write-Warning "Client is already registered." + $CcmRegistered = $true + } + ElseIf ($CcmRegistered -eq $false) { Start-Sleep -Seconds 30 } + } + + Write-Warning -Message "[$FQDN]:Approve SCCM Client" + #Start-Sleep -Seconds 30 # ADD LOOP/SMARTS TO WAIT FOR DISCOVERY AND ANOTHER FOR APPROVAL + Invoke-Command -ComputerName itdsccmp2.nd.gov -Credential $CcmCred -ArgumentList $Hostname -ScriptBlock { + Import-Module 'D:\Program Files\Microsoft Configuration Manager\AdminConsole\bin\ConfigurationManager.psd1' + $PSDrives = Get-PSDrive + If ($PSDrives | Where-Object Name -EQ "ITD") { + # ITD Drive exists, do nothing + } + else { + New-PSDrive -Name "ITD" -PSProvider AdminUI.PS.Provider\CMSite -Root itdsccmp2.nd.gov + } + + Set-Location ITD:\ + $Device = Get-CMDevice -Name $args[0] + If ($Device.IsApproved -eq 0) { + Approve-CMDevice -DeviceName $args[0] + } + } + + Write-Warning "[$FQDN]:Trigger SCCM MachinePolicy First Check-in" + Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText { + [void] ([wmiclass] "\\localhost\root\ccm:SMS_Client").TriggerSchedule("{00000000-0000-0000-0000-000000000021}"); + } + + Write-Warning "[$FQDN]:Trigger SCCM MachinePolicy" + Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText { + [void] ([wmiclass] "\\localhost\root\ccm:SMS_Client").TriggerSchedule("{00000000-0000-0000-0000-000000000021}"); + } + #Start-Sleep -Seconds 180 + + Write-Warning -Message '[$FQDN]:Waiting for network connectivity / Then KVM Activation...' + Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText { + # Pause until network connectivity is available + + $KMS = 'kms.nd.gov' + + try { + $nwJob = Start-Job -Name 'NetworkCheck' -ScriptBlock { + Param ( [String]$KMS ) + do { + $nwStatus = Test-NetConnection -ComputerName $KMS -Port 1688 -InformationLevel Quiet + + Start-Sleep -Seconds 10 + } until($nwStatus) + } -ArgumentList $KMS + + # If after 30 seconds the network connection is not responding continue on + if ((Wait-Job -Job $nwJob -Timeout 30).State -eq 'Completed') { + Write-Verbose -Message 'Network connectivity has been verified.' + } + else { + [void](Stop-Job -Job $nwJob) + Write-Verbose -Message 'Network connectivity could not be verified.' + } + } + catch { + Throw $_ + Break + } + + # Activate via KMS + Write-Verbose -Message "Activating windows against $KMS..." + if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { + Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs; exit + } + try { + cscript C:\Windows\System32\slmgr.vbs /skms $KMS | Out-Null + cscript C:\Windows\System32\slmgr.vbs /ato | Out-Null + + Write-Verbose -Message "Checking activation status..." + + $kmsOut = cscript C:\Windows\System32\slmgr.vbs /dli + + if (($kmsOut | Select-String -Pattern '^License Status:') -match 'Licensed') { + Write-Verbose -Message "Windows successfully activated." + } + else { + Write-Verbose -Message "Windows failed to activate, run slmgr commands manually. Ensure server time is correct." + Write-Warning -Message "Windows failed to activate, run slmgr commands manually. Ensure server time is correct." + } + } + catch { + Throw $_ + Break + } + } + Write-Warning "[$FQDN]:End" +} \ No newline at end of file diff --git a/VMware-AutoSnap.ps1 b/VMware-AutoSnap.ps1 new file mode 100644 index 0000000..6fed5e7 --- /dev/null +++ b/VMware-AutoSnap.ps1 @@ -0,0 +1,22 @@ +$ITD = 'HAKpueFYU4L3NMXTKqtHssnNGBrew3gVRLEq2Yi7yzWW8fpKNCPB5gUcnHfr9sdhXC53y7gWf5BDtxXkr3mZA3NV7DszpR3kjiLgi3FpRPgUWus9ZxCWy63znqPGh3AJ2bn43uP7GjzfLcgqYLQRkir' +$URL = 'https://s1events.azure-automation.net/webhooks?token=VfxwwkSMqH4yiLrWmUfVowEuXBWgkbcBDeX8FFwMbCI%3d' + +$header = @{ITD=$ITD} +$params = @( + @{ + Id = 1986; + SnapshotDuration = 3; + DateTime = '2019-07-29T19:00:00Z'; + Title = "itdscmt1.nd.gov"; + Email = "zmeier@nd.gov"; + } +) + +$body = ConvertTo-Json -InputObject $params +$response = Invoke-WebRequest -Method Post -Uri $URL -Headers $header -Body $body + + +[System.TimeZoneInfo]::ConvertTimeBySystemTimeZoneId( ` + (Get-Date), 'Central Standard Time') + +[System.TimeZoneInfo]::ConvertTimeBySystemTimeZoneId((Get-Date), 'Central Standard Time') \ No newline at end of file diff --git a/VMware-BackupUplinksAndVMKernels.ps1 b/VMware-BackupUplinksAndVMKernels.ps1 new file mode 100644 index 0000000..4ff0cd2 --- /dev/null +++ b/VMware-BackupUplinksAndVMKernels.ps1 @@ -0,0 +1,41 @@ +$ServerList = @" +itdmdnvm-test01.nd.gov +itdmdnvm-test02.nd.gov +itdmdnvm-test03.nd.gov +"@ +$ServerList = ConvertTo-Array -MultiLineString $ServerList +$VMHosts = Get-VMHost $ServerList | sort-object Name +$x = ForEach($VMHost in $VMHosts){ + $EsxCli = $VMHost | Get-EsxCli -V2 + #$StaticRouteBefore = + $EsxCli.network.ip.route.ipv4.list.Invoke() + <# + Gateway : 10.2.168.241 + Interface : vmk2 + Netmask : 255.255.255.192 + Network : 10.2.169.128 + Source : MANUAL + #> + + #$PhysicalAdapter = $VMHost | Get-VMHostNetworkAdapter | where-object {$_.Name -eq "vmnic6" -and $_.Name -eq "vmnic7"} + #$dvSwitch = Get-VDSwitch -Name dvSwitch-TSTMGMT1-Backup +<# + $PortGroup = Get-VDPortGroup -Name dvPG_3532_10.2.168.240_28 + $DNSRecord = Resolve-DnsName -Name ($VMHost.Name.split('.')[0] + 'co.' + $VMHost.Name.split('.')[1] + '.' + $VMHost.Name.split('.')[2]) + + + $VMHost | New-VMHostNetworkAdapter -PortGroup $PortGroup ` + -VirtualSwitch $dvSwitch ` + -IP $DNSRecord.IPAddress ` + -SubnetMask 255.255.255.240 ` + -ManagementTrafficEnabled $true + #> + + #$params = @{ + # network = '10.2.168.128/26' + #} + + + #$EsxCli.network.ip.route.ipv4.add +} + diff --git a/VMware-DatastoreCapacity.ps1 b/VMware-DatastoreCapacity.ps1 new file mode 100644 index 0000000..bcc3be0 --- /dev/null +++ b/VMware-DatastoreCapacity.ps1 @@ -0,0 +1,31 @@ +$Datacenters = Get-Datacenter -Name Primary*, Secondary* +ForEach ($Datacenter in $Datacenters) { + write-warning -Message $Datacenter.name + $DatacenterName = $Datacenter.Name + $Datastores = $Datacenter | Get-Datastore -Name *FS92* + + $result = [System.Collections.ArrayList]@() + ForEach ($Datastore in $Datastores) { + write-warning -Message $Datastore.name + $VMsOnDatastore = $null + + $VMsOnDatastore = $Datastore | Get-VM + $VMDKsOnDatastore = $VMsOnDatastore | Get-HardDisk | Where-Object Filename -Match $Datastore.Name + + + $obj = [PSCustomObject]@{ + 'DatastoreName' = $Datastore.Name; + 'UsedSpaceGB' = [math]::round($Datastore.CapacityGB - $Datastore.FreeSpaceGB, 2); + #'FreeSpaceGB' = [math]::round($Datastore.FreeSpaceGB, 2); + 'CapacityGB' = [math]::round($Datastore.CapacityGB, 2); + 'PercentUsed' = [math]::round(($Datastore.CapacityGB - $Datastore.FreeSpaceGB) / $Datastore.CapacityGB, 2); + #'VMUsedSpaceGB' = [math]::round(($VMsOnDatastore | Measure-Object -Sum UsedSpaceGB).Sum, 2); + #'VMProvisionedGB' = [math]::round(($VMsOnDatastore | Measure-Object -Sum ProvisionedSpaceGB).Sum, 2); + #'VMPercentUsed' = [math]::round(($VMsOnDatastore | Measure-Object -Sum UsedSpaceGB).Sum / ($VMsOnDatastore | Measure-Object -Sum ProvisionedSpaceGB).Sum , 2); + } + + $null = $result.Add($obj) + } + $Date = Get-Date -UFormat %Y%m%d + $result | Export-Csv -Path "D:\State of North Dakota\-Tm-ITD-Virtualization - Documents\FS9200 Overprovision Fixes\FS9200-$DatacenterName-$Date.csv" +} \ No newline at end of file diff --git a/VMware-DisableAlarms.ps1 b/VMware-DisableAlarms.ps1 new file mode 100644 index 0000000..8f4c9d1 --- /dev/null +++ b/VMware-DisableAlarms.ps1 @@ -0,0 +1,119 @@ +function Set-AlarmActionState { + <# + .SYNOPSIS Enables or disables Alarm actions + .DESCRIPTION The function will enable or disable + alarm actions on a vSphere entity itself or recursively + on the entity and all its children. + .NOTES Author: Luc Dekens + .PARAMETER Entity + The vSphere entity. + .PARAMETER Enabled + Switch that indicates if the alarm actions should be + enabled ($true) or disabled ($false) + .PARAMETER Recurse + Switch that indicates if the action shall be taken on the + entity alone or on the entity and all its children. + .EXAMPLE + PS> Set-AlarmActionState -Entity $cluster -Enabled:$true + #> + param( + [CmdletBinding()] + [Parameter(Mandatory=$true,ValueFromPipeline=$true)] + [VMware.VimAutomation.ViCore.Impl.V1.Inventory.InventoryItemImpl]$Entity, + [switch]$Enabled, + [switch]$Recurse + ) + begin{ + $alarmMgr = Get-View AlarmManager + } + process{ + if($Recurse){ + $objects = @($Entity) + $objects += Get-Inventory -Location $Entity + } + else{ + $objects = $Entity + } + $objects | %{ + $alarmMgr.EnableAlarmActions($_.Extensiondata.MoRef,$Enabled) + } + } + } + function Get-ITDVMwareAlarmActionState + { + [CmdletBinding()] + param + ( + + [Parameter(Mandatory=$true,ValueFromPipeline=$true)] + [VMware.VimAutomation.ViCore.Impl.V1.Inventory.InventoryItemImpl]$Entity, + [switch]$Recurse = $false + ) + process { + $Entity = Get-Inventory -Id $Entity.Id + if($Recurse){ + $objects = @($Entity) + $objects += Get-Inventory -Location $Entity + } + else{ + $objects = $Entity + } + $objects | + Select Name, + @{N="Type";E={$_.GetType().Name.Replace("Impl","").Replace("Wrapper","")}}, + @{N="Alarm actions enabled";E={$_.ExtensionData.alarmActionsEnabled}} + } + } + + + +<# +.SYNOPSIS + Short description +.DESCRIPTION + Long description +.EXAMPLE + Example of how to use this cmdlet +.EXAMPLE + Another example of how to use this cmdlet +.INPUTS + Inputs to this cmdlet (if any) +.OUTPUTS + Output from this cmdlet (if any) +.NOTES + General notes +.COMPONENT + The component this cmdlet belongs to +.ROLE + The role this cmdlet belongs to +.FUNCTIONALITY + The functionality that best describes this cmdlet +#> +function Get-ITDVMwareAlarmActionState +{ + [CmdletBinding()] + Param + ( + [Parameter(Mandatory=$true,ValueFromPipeline=$true)] + [VMware.VimAutomation.ViCore.Impl.V1.Inventory.InventoryItemImpl]$Entity, + + [switch $Enabled, + [switch]$Recurse + + ) + + begin + { + + } + + process + { + + } + + end + { + + } +} \ No newline at end of file diff --git a/VMware-DiskInventory.ps1 b/VMware-DiskInventory.ps1 new file mode 100644 index 0000000..69d9d8b --- /dev/null +++ b/VMware-DiskInventory.ps1 @@ -0,0 +1,20 @@ +$VMs = Get-VM | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" } + +$result = [System.Collections.ArrayList]@() +ForEach ($VM in $VMs) { + $Disks = $VM | Get-HardDisk + $TotalThreads = $Disks.count + $256GBDisks = ($Disks | where-object CapacityGB -gt 256) + + $obj = [PSCustomObject]@{ + 'ComputerName' = $VM.Name; + 'NumOfDisks' = $Disks.count + 'NumOver256GB' = $256GBDisks.count + #'NumOf256GBThreads' = $TotalThreads + } + + #Write-Output $obj + $null = $result.Add($obj) +} + +$result \ No newline at end of file diff --git a/VMware-EVC.ps1 b/VMware-EVC.ps1 new file mode 100644 index 0000000..df0d8e0 --- /dev/null +++ b/VMware-EVC.ps1 @@ -0,0 +1,21 @@ +[string]$Cluster_str = "WINDOWS1" +#ForEach ($Cluster_str in (Get-Cluster | Sort-object Name).Name) { + Write-Warning $Cluster_str + $x=Get-View -ViewType ClusterComputeResource -Property Name, Summary -Filter @{"Name" = $Cluster_str } | Foreach-Object { + $viewThisCluster = $_ + Get-View -ViewType VirtualMachine -Property Name, Runtime.PowerState, Summary.Runtime.MinRequiredEVCModeKey -SearchRoot $viewThisCluster.MoRef | Foreach-Object { + $z = $_ + New-Object -Type PSObject -Property ([ordered]@{ + Name = $_.Name + PowerState = $_.Runtime.PowerState + VMEVCMode = $_.Summary.Runtime.MinRequiredEVCModeKey + ClusterEVCMode = $viewThisCluster.Summary.CurrentEVCModeKey + ClusterName = $viewThisCluster.Name + #VMHost = (Get-VM $_.Name | Get-VMHost).Name + }) + + } + } +#} + +$x | where-object { $_.VMEVCMode -eq 'intel-broadwell' -or $_.VMEVCMode -eq 'intel-haswell' } | Format-Table \ No newline at end of file diff --git a/VMware-FixCoresPerSocket.ps1 b/VMware-FixCoresPerSocket.ps1 new file mode 100644 index 0000000..7465e22 --- /dev/null +++ b/VMware-FixCoresPerSocket.ps1 @@ -0,0 +1,20 @@ +$import = import-csv D:\VMsToFix.csv #| where-object Name -eq itdvmvc1script.nd.gov + +Get-VM ($import).Name | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" } | Stop-VMGuest -Confirm:$false + +ForEach($VM in $import){ + Get-VM $VM.Name | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" } | Stop-VMGuest -Confirm:$false +} + +# status check +Get-VM -Name ($import).Name | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" } | group-object PowerState + + +# report +Get-VM -Name ($import).Name | Select Name,PowerState,NumCpu,CoresPerSocket -ov BeforeChange +$BeforeChange | Export-Csv "D:\BeforeChange.csv" + +Get-VM -Name ($import).Name | Set-VM -CoresPerSocket 1 -Confirm:$false + +Get-VM -Name ($import).Name | Select Name,PowerState,NumCpu,CoresPerSocket +#Get-VM -Name ($import).Name | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" } | Start-VM \ No newline at end of file diff --git a/VMware-HA.ps1 b/VMware-HA.ps1 new file mode 100644 index 0000000..6ad8c58 --- /dev/null +++ b/VMware-HA.ps1 @@ -0,0 +1,16 @@ +$Clusters = get-datacenter Primary*, Secondary* | get-cluster | sort-object Name +$Clusters | ForEach-Object{ + $_ | Set-Cluster -HAEnabled $false -DrsEnabled $false -Confirm:$false +} + +$Clusters = get-datacenter Primary*, Secondary* | get-cluster | sort-object Name +$Clusters | ForEach-Object{ + If($_.Name -like "AVAYA*" -or $_.Name -like "TEL*"){ + $_ | Set-Cluster -HAEnabled $true -Confirm:$false + } + Else{ + $_ | Set-Cluster -HAEnabled $true -DrsEnabled $true -Confirm:$false + } +} + +#avaya/tel no DRS \ No newline at end of file diff --git a/VMware-Host Network Config.ps1 b/VMware-Host Network Config.ps1 new file mode 100644 index 0000000..129a23b --- /dev/null +++ b/VMware-Host Network Config.ps1 @@ -0,0 +1,20 @@ +# vMotion Switch +Get-VDSwitch dvSwitch-TEST2-vMotion | Add-VDSwitchVMHost -VMHost itdvmmdntest06.nd.gov -Confirm:$false +$physicalNIC = Get-VMHost itdvmmdntest06.nd.gov | Get-VMHostNetworkAdapter -Physical -Name vmnic4,vmnic5 +Get-VDSwitch dvSwitch-TEST2-vMotion | Add-VDSwitchPhysicalNetworkAdapter -VMHostPhysicalNic $physicalNIC +Get-VMHost itdvmmdntest06.nd.gov | New-VMHostNetworkAdapter -VirtualSwitch dvSwitch-TEST2-vMotion -PortGroup dvPG_3637_10.2.136.128_26_kernel -confirm:$false +Get-VMHost itdvmmdntest06.nd.gov | Get-VMHostNetworkAdapter -VMKernel -Name vmk1 | Set-VMHostNetworkAdapter -IP 10.2.136.159 -SubnetMask 255.255.255.192 -VMotionEnabled $true -confirm:$false + +# Data-Server +Get-VDSwitch dvSwitch-TEST2-Data-Server | Add-VDSwitchVMHost -VMHost itdvmmdntest06.nd.gov -Confirm:$false +$physicalNIC = Get-VMHost itdvmmdntest06.nd.gov | Get-VMHostNetworkAdapter -Physical -Name vmnic6,vmnic7 -confirm:$false +Get-VDSwitch dvSwitch-TEST2-Data-Server | Add-VDSwitchPhysicalNetworkAdapter -VMHostPhysicalNic $physicalNIC -confirm:$false + +# Backup +Get-VDSwitch dvSwitch-TEST2-Backup | Add-VDSwitchVMHost -VMHost itdvmmdntest06.nd.gov -Confirm:$false +$physicalNIC = Get-VMHost itdvmmdntest06.nd.gov | Get-VMHostNetworkAdapter -Physical -Name vmnic8,vmnic9 +Get-VDSwitch dvSwitch-TEST2-Backup | Add-VDSwitchPhysicalNetworkAdapter -VMHostPhysicalNic $physicalNIC -confirm:$false +Get-VMHost itdvmmdntest06.nd.gov | New-VMHostNetworkAdapter -VirtualSwitch dvSwitch-TEST2-Backup -PortGroup dvPG_3532_10.2.168.240_28 -confirm:$false +Get-VMHost itdvmmdntest06.nd.gov | Get-VMHostNetworkAdapter -VMKernel -Name vmk2 | Set-VMHostNetworkAdapter -IP 10.2.168.246 -SubnetMask 255.255.255.240 -confirm:$false + + diff --git a/VMware-HostInventory.ps1 b/VMware-HostInventory.ps1 new file mode 100644 index 0000000..f1b27e3 --- /dev/null +++ b/VMware-HostInventory.ps1 @@ -0,0 +1,36 @@ +$iLOs = Find-HPEiLO -Range "10.8.144.0-255" +$iLOs += Find-HPEiLO -Range "10.8.145.0-255" +$iLOs += Find-HPEiLO -Range "10.8.146.0-255" +$iLOs += Find-HPEiLO -Range "10.8.147.0-255" +$iLOs += Find-HPEiLO -Range "10.8.148.0-255" +$iLOs += Find-HPEiLO -Range "10.8.149.0-255" +$iLOs += Find-HPEiLO -Range "10.8.150.0-255" +$iLOs += Find-HPEiLO -Range "10.8.151.0-255" + +$iLOs = Find-HPEiLO -Range "10.8.144-151" -Full + +$ilos | export-csv "D:\OneDrive - State of North Dakota\iLOs.csv" + +$Connection = $iLOs | Connect-HPEiLO -Credential $AdminCred +$AllTags = Get-HPEiLOAssetTag -Connection $Connection +$result = @() +ForEach($ilo in $iLOs) +{ + $Hostname = $ilo.hostname -replace 'lo' + $VMhost = Get-VMhost $Hostname + $obj=[PSCustomObject]@{ + Hostname = $Hostname; + IPAddress = (Resolve-DNSName $Hostname).IPAddress + Model = $iLO.HostSystemInformation.SPN; + SerialNumber = $iLO.HostSystemInformation.SerialNumber; + AssetTag = ($AllTags | where-object Hostname -eq $iLO.Hostname).AssetTag; + Rack = $ilo.BladeSystem.Manager.Rack; + Enclosure = $ilo.BladeSystem.Manager.Enclosure; + Bay = $ilo.BladeSystem.Bay; + CPU = $VMhost.NumCpu; + Memory = [math]::round($VMhost.MemoryTotalGB,2); + Cluster = ($VMHost | Get-Cluster).Name; + } + + $result += $obj +} \ No newline at end of file diff --git a/VMware-HostInventoryV2.ps1 b/VMware-HostInventoryV2.ps1 new file mode 100644 index 0000000..3014c83 --- /dev/null +++ b/VMware-HostInventoryV2.ps1 @@ -0,0 +1,25 @@ +$AllVMHosts = Get-VMHost + +$Result = [System.Collections.ArrayList]@() + +ForEach($VMHost in $AllVMHosts){ + $EsxCli = $VMHost | Get-EsxCli -V2 + + $obj = [PSCustomObject]@{ + Name = $VMHost.Name; + SerialNumber = $EsxCli.hardware.platform.get.Invoke().SerialNumber; + AssetNumber = ($VMhost.ExtensionData.Summary.Hardware.OtherIdentifyingInfo | select IdentifierValue,@{n='Label';e={$_.IdentifierType.Label}} | where-object Label -eq "Asset Tag")."Asset Tag"; + Model = $VMHost.Model; + CPU = $VMHost.ProcessorType; + CPU_ClockGHz = $VMHost.ProcessorType.split('@ ')[1] -replace 'GHz'; + CPU_Sockets = $VMHost.Extensiondata.Summary.Hardware.NumCpuPkgs; + CPU_TotalCores = $VMHost.Extensiondata.Summary.Hardware.NumCpuCores; + MemoryTotalGB = $VMHost.MemoryTotalGB + Location = ''; + Enclosure = ''; + } + + $null = $Result.Add($obj) +} + +$Result | Export-Csv "C:\users\zmeier\desktop\hostinventory.csv" \ No newline at end of file diff --git a/VMware-HostTags.ps1 b/VMware-HostTags.ps1 new file mode 100644 index 0000000..20d41d6 --- /dev/null +++ b/VMware-HostTags.ps1 @@ -0,0 +1,27 @@ +$OvConnections = Connect-OVMgmt -Hostname itdbissyncompp1.nd.gov -Credential $PrvCred -AuthLoginDomain nd.gov -LoginAcknowledge +Connect-ITDvCenter -Credential $PrvCred + +$OvServers = Get-OVServer + +ForEach ($OvServer in $OvServers) { + $VMHost = $null + $VMHost = Get-VMHost -Name ($OvServer.serverName) + $ViServer = $VMHost.Uid.split('@')[1].split(':')[0] + + If ($VMHost) { + $OldTag = Get-TagAssignment -Entity $VMHost -Category "HPE Enclosure" + $NewTag = Get-Tag -Category "HPE Enclosure" -Name $OvServer.Name.split('_')[0] -Server $ViServer + + If ($OldTag.Tag -eq $NewTag) { + Write-Warning "$VMhost tag correct" + } + else { + Write-Warning "$VMhost tag incorrect, fixing" + Get-TagAssignment -Entity $VMHost -Category "HPE Enclosure" | Remove-TagAssignment -Confirm:$false -ErrorAction SilentlyContinue + $VMHost | New-TagAssignment -Tag $NewTag + } + } + Else { + Write-Warning "vmhost error" + } +} \ No newline at end of file diff --git a/VMware-IndPerDiskInfo.ps1 b/VMware-IndPerDiskInfo.ps1 new file mode 100644 index 0000000..a09fc38 --- /dev/null +++ b/VMware-IndPerDiskInfo.ps1 @@ -0,0 +1,37 @@ +$VMs = Get-DatastoreCluster WINDOWS1* | Get-Datastore | Get-VM +$VMInfo = $VMs | Select Name, @{n='ProvisionedSpaceGBr';e={[math]::round($_.ProvisionedSpaceGB,2)}}, @{n='UsedSpaceGBr';e={[math]::round($_.UsedSpaceGB,2)}}, @{n = 'IndPer'; e = { If (($_ | get-harddisk | where-object Persistence -eq IndependentPersist).count -gt 0) { $true }Else { $false } } }, @{n='Datastore';e={($_ | Get-HardDisk).Filename.split(' ')[0]}} + +$IndPerVMs = $VMInfo | where-object name -ne "itdhpnvid.nd.gov" | where-object IndPer -eq $true | measure-object -Sum ProvisionedSpaceGBr, UsedSpaceGBr +$PersistVMs = $VMInfo | where-object name -ne "itdhpnvid.nd.gov" | where-object IndPer -eq $false | measure-object -sum ProvisionedSpaceGBr, UsedSpaceGBr + +# manual sort data +$VMInfo | where-object Name -ne itdhpnvid.nd.gov | where-object IndPer -eq $true | sort-object UsedSpaceGBr -Descending | ft + + +# i don't remember specifics why this exists: +$result=@() +$VMs | ForEach-Object{ + $disks = $_ | Get-HardDisk | select *,@{n='Datastore';e={$_.Filename.split(' ')[0]}} + + $obj=[PSCustomObject]@{ + Name = $_.Name; + Count = @($disks.Datastore | select -unique).count; + Datastores = $disks.Datastore | select -unique; + } + $result += $obj +} +$result + + + +$BisSQLVMs=[System.Collections.ArrayList]@() +$BisSQLVMs += Get-DatastoreCluster WINDOWS1* | Get-VM -Tag 'SQL MSDN' -Server itdvmvc1.nd.gov | where-object Name -ne 'itdhpnvid.nd.gov' | sort-object Name +$BisSQLVMs += Get-DatastoreCluster WINDOWS1* | Get-VM -Tag 'SQL Enterprise Academic' -Server itdvmvc1.nd.gov | where-object Name -ne 'itdhpnvid.nd.gov' | sort-object Name +$BisSQLVMs += Get-DatastoreCluster WINDOWS1* | Get-VM -Tag 'SQL Standard' -Server itdvmvc1.nd.gov | where-object Name -ne 'itdhpnvid.nd.gov' | sort-object Name +$BisSQLVMs = $BisSQLVMs | sort-object -Descending ProvisionedSpaceGB + +$MdnSQLVMs=[System.Collections.ArrayList]@() +$MdnSQLVMs += Get-DatastoreCluster WINDOWS2* | Get-VM -Tag 'SQL MSDN' -Server itdvmvc2.nd.gov | sort-object Name +$MdnSQLVMs += Get-DatastoreCluster WINDOWS2* | Get-VM -Tag 'SQL Enterprise Academic' -Server itdvmvc2.nd.gov | sort-object Name +$MdnSQLVMs += Get-DatastoreCluster WINDOWS2* | Get-VM -Tag 'SQL Standard' -Server itdvmvc2.nd.gov | sort-object Name +$MdnSQLVMs = $MdnSQLVMs | sort-object -Descending ProvisionedSpaceGB \ No newline at end of file diff --git a/VMware-LastPowerOnPowerOff.ps1 b/VMware-LastPowerOnPowerOff.ps1 new file mode 100644 index 0000000..3e8d445 --- /dev/null +++ b/VMware-LastPowerOnPowerOff.ps1 @@ -0,0 +1,43 @@ +$Report = @() + +$VMs = get-vm -name itdtufin.nd.gov + +$Datastores = Get-Datastore | select Name, Id + +Get-VIEvent -Entity $VMs -MaxSamples ([int]::MaxValue) -ov x | + +$x | where {$_ -is [VMware.Vim.VmPoweredOnEvent] -or $_ -is [VMware.Vim.VmPoweredOffEvent]} -ov y| + +Group-Object -Property {$_.Vm.Name} | %{ + + $lastPO = $_.Group | Sort-Object -Property CreatedTime -Descending | Select -First 1 + + $vm = Get-VM -Name $_.Name + + $row = '' | select VMName,Powerstate,OS,Host,Cluster,Datastore,NumCPU,MemMb,DiskGb,PowerOFF + + $row.VMName = $vm.Name + + $row.Powerstate = $vm.Powerstate + + $row.OS = $vm.Guest.OSFullName + + $row.Host = $vm.VMHost.name + + $row.Cluster = $vm.VMHost.Parent.Name + + $row.Datastore = ($Datastores | where {$_.ID -match (($vm.Datastore | Select -First 1) | Select Value).Value} | Select Name).Name + + $row.NumCPU = $vm.NumCPU + + $row.MemMb = $vm.MemoryMB + + $row.DiskGb = ((($vm.HardDisks | Measure-Object -Property CapacityKB -Sum).Sum * 1KB / 1GB),2) + + $row.PowerOFF = $lastPO.CreatedTime + + $report += $row + +} + +$report | Sort Name | Export-Csv -Path "C:\XXXXX\Powered_Off_VMs.csv" -NoTypeInformation -UseCulture \ No newline at end of file diff --git a/VMware-ManualBackupViaClone.ps1 b/VMware-ManualBackupViaClone.ps1 new file mode 100644 index 0000000..8501444 --- /dev/null +++ b/VMware-ManualBackupViaClone.ps1 @@ -0,0 +1,38 @@ +$VMs = Get-VM itdprint1a.nd.gov,itdprint1b.nd.gov | where-object PowerState -eq PoweredOn +$count=0 +ForEach ($VM in $VMs) +{ + $count++ + $Cluster = $null + $DatastoreCluster = $null + $DatastoreLargest = $null + $DatastoreDestination = $Null + $vCenter = $null + $Templ = $null + + $vCenter = $VM.uid.split('@')[1].split('.')[0] + $TEMPL = Get-Datastore "*TEMPL*" | where-object Uid -like "*$vCenter*" + + $Cluster = $VM | Get-Cluster + $DatastoreCluster = $VM | Get-DatastoreCluster + $DatastoreLargest = $DatastoreCluster | Get-Datastore | sort-object FreeSpaceGB -Descending | select -first 1 + + If($DatastoreLargest.FreeSpaceGB -gt $VM.UsedSpaceGB) + { + $DatastoreDestination = $DatastoreCluster + } + Else + { + $DatastoreDestination = $TEMPL + } + + If($Count -le 8) + { + New-VM -VM $VM -Name ($VM.Name + "_backup20191021") -ResourcePool $Cluster -Datastore $DatastoreDestination -RunAsync + } + else { + New-VM -VM $VM -Name ($VM.Name + "_backup20191021") -ResourcePool $Cluster -Datastore $DatastoreDestination + start-sleep -seconds 180 + $count = 0 + } +} \ No newline at end of file diff --git a/VMware-ManualDisk.ps1 b/VMware-ManualDisk.ps1 new file mode 100644 index 0000000..a4770ff --- /dev/null +++ b/VMware-ManualDisk.ps1 @@ -0,0 +1,70 @@ +$disks = Get-DatastoreCluster SQL2_A9K_General_KeepTogether | Get-Datastore | Get-vm | get-harddisk | select Parent,CapacityGB,Persistence,@{n='Datastore';e={$_.Filename.split(' ')[0]}} +$disks | where-object Datastore -notlike "*CND*" | sort-object CapacityGB -Descending + + +$disks | where-object Datastore -notlike "*CND*" | where-object Persistence -like "IndependentPersistent" | where-object {$_.Datastore -notlike "*171*" -or $_.Datastore -notlike "*174*" -and $_.Datastore -notlike "*175*" -and $_.Datastore -notlike "*176*" -and $_.Datastore -notlike "*177*" -and $_.Datastore -notlike "*178*" -and $_.Datastore -notlike "*185*"} + +$VMSize = @() +$disks | group-object Parent | ForEach-Object { + $obj=[PSCustomObject]@{ + 'VM' = $_.Name; + 'SizeGB' = ($_.Group | measure-object CapacityGB -sum).sum + } + $VMSize += $obj +} +#### MOVE _CND NEXT + + +$disks = Get-DatastoreCluster SQL2_A9K_General | Get-Datastore | Get-vm | get-harddisk | select Parent,CapacityGB,Persistence,@{n='Datastore';e={$_.Filename.split(' ')[0]}} +$disks | group-object Parent | ForEach-Object{ + $_.Group | where-object Persistence -eq IndependentPersistent | sort-object CapacityGB -Descending | select -first 1 +} + +$disks | group-object Parent | select Name,@{n='MaxIPDiskSizeGB';e={($_.Group | Where-Object Persistence -eq IndependentPersistent | sort-object CapacityGB -Descending | select -first 1).CapacityGB}},@{n='MaxIPDiskDatastore';e={($_.Group | Where-Object Persistence -eq IndependentPersistent | sort-object CapacityGB -Descending | select -first 1).Datastore}},@{n='TotalSizeGB';e={($_.group | measure-object CapacityGB -Sum).Sum}},@{n='DatastoreCount';e={@($_.group).count }} | sort-object MaxIPDiskSizeGB -Descending | ft + + + + +$VMs = Get-DatastoreCluster SQL1_A9K_General | Get-VM +$AllDisks = $VMs | Get-HardDisk | select Parent,CapacityGB,Persistence,@{n='Datastore';e={$_.Filename.split(' ')[0]}} + +$result = @() +ForEach($VM in $VMs) +{ + $VMDisks = $VM | Get-HardDisk | select Parent,CapacityGB,Persistence,@{n='Datastore';e={$_.Filename.split(' ')[0]}} + If(($VMDisks | select -Unique Datastore).count -gt 1) + { + $obj=[PSCustomObject]@{ + 'VMName' = $VM.Name; + 'SumGB' = (Get-VM $VM.Name | Get-HardDisk | measure-object CapacityGB -Sum).Sum; + } + $result += $obj + } +} +$result | sort-object SumGB -Descending + + + + + +<# Manual SQL SDRS +- get amount of space required to find a home for +- find datastore with the most VMs under under 2TB +- do those VMs take up more space than desired amount? + - if yes, move VMs to other datastores + - create new object with before and after usage + - find largest VM in group, move to datastore with highest free space + - repeat until enough specified space exists + - if no, find datastore with the most free space + - create new object with before and after usage + - move the largest vm on that datastore to the datastore with the 2nd most free space + - repeat until enough specified space exists + +# > + + +169 + +*Select "Change" only if changes need to go to VM admins. + +*Select "Delete" to have the VM removed and permanently deleted \ No newline at end of file diff --git a/VMware-ModuleList.ps1 b/VMware-ModuleList.ps1 new file mode 100644 index 0000000..76692d9 --- /dev/null +++ b/VMware-ModuleList.ps1 @@ -0,0 +1,9 @@ +$esxcli = Get-EsxCli -VMHost itdvmbiswin11.nd.gov -V2 +$AllKernelModules = $esxcli.system.module.list.invoke() + +$Result = [System.Collections.ArrayList]@() +ForEach($KernelModule in $AllKernelModules){ + $params=@{module=$KernelModule.Name} + $null = $MyArrayList.Add($esxcli.system.module.get.invoke($params)) +} +$Result \ No newline at end of file diff --git a/VMware-MoveToA9K.ps1 b/VMware-MoveToA9K.ps1 new file mode 100644 index 0000000..bd68868 --- /dev/null +++ b/VMware-MoveToA9K.ps1 @@ -0,0 +1,16 @@ +$VMsToMove = Get-DatastoreCluster *linux*V5K* | Get-VM | where-object Name -like "itddhs*" | sort-object UsedSpaceGB + +ForEach($VM in $VMsToMove){ + Write-Warning ($VM.Name + ' ... ' + [math]::round($VM.UsedSpaceGB,2)) + $wait = $true + while ($wait -eq $true) + { + $tasks = Get-Task | where-object {$_.Name -like "ApplyStorageDrs*" -and $_.State -eq "Running"} + If(@($Tasks).count -lt 1){$wait = $false} + Else{$wait=$true; Write-Warning ("[$VM]:Start sleep " + (Get-Date) + " DRS Count: " + @($Tasks).count); start-sleep -Seconds 20} + } + $Source = $VM | Get-DatastoreCluster + $Destination = Get-DatastoreCluster -Name ($Source.Name.split('_')[0] + "_A9K_General") + Move-VM -VM $VM -Datastore $Destination -RunAsync + Start-Sleep -Seconds 10 +} \ No newline at end of file diff --git a/VMware-MoveToFS9Bis.ps1 b/VMware-MoveToFS9Bis.ps1 new file mode 100644 index 0000000..888addf --- /dev/null +++ b/VMware-MoveToFS9Bis.ps1 @@ -0,0 +1,44 @@ +Connect-VIServer itdvmvc1.nd.gov -Credential $PrvCred + +$BisSQLVMs = [System.Collections.ArrayList]@() +$BisSQLVMs += Get-DatastoreCluster WINDOWS1* | Get-VM -Tag 'SQL MSDN' | sort-object Name +$BisSQLVMs += Get-DatastoreCluster WINDOWS1* | Get-VM -Tag 'SQL Enterprise Academic' | sort-object Name +$BisSQLVMs += Get-DatastoreCluster WINDOWS1* | Get-VM -Tag 'SQL Standard' | sort-object Name +$BisSQLVMs = $BisSQLVMs | sort-object -Descending ProvisionedSpaceGB + + +# SQL / IndPer first +ForEach ($VM in $BisSQLVMs) { + $DatastoreDestination = Get-DatastoreCluster WINDOWS1_FS92_SQL + $VM | Move-VM -DiskStorageFormat Thick -Datastore $DatastoreDestination +} + +$BisVMs = Get-DatastoreCluster WINDOWS1_A9K_General | Get-VM | Sort-Object -Descending UsedSpaceGB +$DatastoreDestination = Get-DatastoreCluster WINDOWS1_FS92_General +ForEach ($VM in $BisVMs) { + $wait = $true + $DatastoreHighestFreeSpaceGB = $DatastoreDestination | Get-Datastore | Sort-Object -Descending FreeSpaceGB | Select -First 1 + If($VM.UsedSpaceGB -gt $DatastoreHighestFreeSpaceGB.FreeSpace) + { + While ($wait -eq $true) { + $tasks = Get-Task | where-object { $_.Name -like "Relocate*" -or $_.Name -like "ApplyStorageDrsRecommendation*" } | where-object { $_.State -eq "Running" } + If (@($tasks).count -lt 3) { + $wait = $false + } + else { + $wait = $true + Write-Warning ("[$VM]:Start sleep " + (Get-Date)) + Write-Verbose @($tasks).count + Start-Sleep -Seconds 20 + } + } + $VM | Move-VM -Datastore $DatastoreDestination + Start-Sleep -Seconds 10 + } + Else + { + Write-Error ("Not enough free space available for " + $VM.Name + ". Available: " + $DatastoreHighestFreeSpaceGB.FreeSpaceGB + "GB available, " + $VM.UsedSpaceGB + "GB required.") -ErrorAction Stop + Stop + Exit + } +} \ No newline at end of file diff --git a/VMware-MoveToFS9Mdn.ps1 b/VMware-MoveToFS9Mdn.ps1 new file mode 100644 index 0000000..210f059 --- /dev/null +++ b/VMware-MoveToFS9Mdn.ps1 @@ -0,0 +1,53 @@ +Connect-VIServer itdvmvc2.nd.gov -Credential $PrvCred + +$MdnSQLVMs = [System.Collections.ArrayList]@() +$MdnSQLVMs += Get-DatastoreCluster WINDOWS2* | Get-VM -Tag 'SQL MSDN' -Server itdvmvc2.nd.gov | sort-object Name +$MdnSQLVMs += Get-DatastoreCluster WINDOWS2* | Get-VM -Tag 'SQL Enterprise Academic' -Server itdvmvc2.nd.gov | sort-object Name +$MdnSQLVMs += Get-DatastoreCluster WINDOWS2* | Get-VM -Tag 'SQL Standard' -Server itdvmvc2.nd.gov | sort-object Name +$MdnSQLVMs = $MdnSQLVMs | sort-object -Descending ProvisionedSpaceGB + +# SQL / IndPer first +ForEach ($VM in $MdnSQLVMs) { + $DatastoreDestination = Get-DatastoreCluster WINDOWS2_FS92_SQL + $DatastoreHighestFreeSpaceGB = $DatastoreDestination | Get-Datastore | Sort-Object -Descending FreeSpaceGB | Select -First 1 + If($VM.ProvisionedSpaceGB -lt $DatastoreHighestFreeSpaceGB.FreeSpace) + { + $VM | Move-VM -DiskStorageFormat Thick -Datastore $DatastoreDestination + } + Else + { + Write-Error ("Not enough free space available for " + $VM.Name + ". Available: " + $DatastoreHighestFreeSpaceGB.FreeSpaceGB + "GB available, " + $VM.UsedSpaceGB + "GB required.") -ErrorAction Stop + Stop + Exit + } +} + +$MdnVMs = Get-DatastoreCluster WINDOWS2_A9K_General | Get-VM | Sort-Object -Descending UsedSpaceGB +$DatastoreDestination = Get-DatastoreCluster WINDOWS2_FS9_General +ForEach ($VM in $MdnVMs) { + $wait = $true + $DatastoreHighestFreeSpaceGB = $DatastoreDestination | Get-Datastore | Sort-Object -Descending FreeSpaceGB | Select -First 1 + If($VM.UsedSpaceGB -gt $DatastoreHighestFreeSpaceGB.FreeSpace) + { + While ($wait -eq $true) { + $tasks = Get-Task | where-object { $_.Name -like "Relocate*" -or $_.Name -like "ApplyStorageDrsRecommendation*" } | where-object { $_.State -eq "Running" } + If (@($tasks).count -lt 3) { + $wait = $false + } + else { + $wait = $true + Write-Warning ("[$VM]:Start sleep " + (Get-Date)) + Write-Verbose @($tasks).count + Start-Sleep -Seconds 20 + } + } + $VM | Move-VM -Datastore $DatastoreDestination + Start-Sleep -Seconds 10 + } + Else + { + Write-Error ("Not enough free space available for " + $VM.Name + ". Available: " + $DatastoreHighestFreeSpaceGB.FreeSpaceGB + "GB available, " + $VM.UsedSpaceGB + "GB required.") -ErrorAction Stop + Stop + Exit + } +} \ No newline at end of file diff --git a/VMware-NewHostIPDNS.ps1 b/VMware-NewHostIPDNS.ps1 new file mode 100644 index 0000000..3150704 --- /dev/null +++ b/VMware-NewHostIPDNS.ps1 @@ -0,0 +1,21 @@ + +$VMHostNames = @" +itdvmbissqla01.nd.gov +itdvmbissqla02.nd.gov +itdvmmdnsqla01.nd.gov +"@ +$VMHostNames = ConvertTo-Array -MultiLineString $VMHostNames + + +$Int = 106 +$TestIpResult = @("10.8.146.","10.8.142.","10.2.170.") | ForEach-Object { + Resolve-DnsName -Name ($_ + $int) +} +$TestIpResult + +$VMHostName = 'itdvmmdnsqla01' +New-ITDIbDNSRecord -Credential $RadiusCred -IPv4Address "10.8.146.$int" -Hostname "$VMHostName.nd.gov" +New-ITDIbDNSRecord -Credential $RadiusCred -IPv4Address "10.8.142.$int" -Hostname "$VMHostName-mot.nd.gov" +New-ITDIbDNSRecord -Credential $RadiusCred -IPv4Address "10.2.170.$int" -Hostname "$VMHostName-bak.nd.gov" + +$VMHostName | ForEach-Object {New-ITDPassword -PasswordList VMware_Systems -Title $_ -Description "local admin" -AccountType "VMware ESXi" -UserName root -Credential $PrvCred} diff --git a/VMware-NewHostWWPNs.ps1 b/VMware-NewHostWWPNs.ps1 new file mode 100644 index 0000000..4d3902e --- /dev/null +++ b/VMware-NewHostWWPNs.ps1 @@ -0,0 +1,33 @@ + +$VMHostNames = @" +itdvmbissqla01.nd.gov +itdvmbissqla02.nd.gov +itdvmmdnsqla01.nd.gov +"@ +$VMHostNames = ConvertTo-Array -MultiLineString $VMHostNames + +$result = [System.Collections.ArrayList]@() + +ForEach ($VMHostName in $VMHostNames) +{ + $VMHostHba = Get-VMHostHba -VMHost $VMHostName -Type FibreChannel | Sort-Object Device + + $obj=[PSCustomObject]@{ + 'VMHostName' = $VMHostName; + 'WWPNa' = $VMHostHba[0].PortWorldWideName + 'WWPNb' = $VMHostHba[1].PortWorldWideName + } + + #Write-Output $obj + $null = $result.Add($obj) +} + +$result + + +$result | ForEach-Object{ + Write-Host $_.VMHostName + Write-Host $_.WWPNa + Write-Host $_.WWPNb + Write-Host "" +} \ No newline at end of file diff --git a/VMware-OfflineSnapshots.ps1 b/VMware-OfflineSnapshots.ps1 new file mode 100644 index 0000000..bf53a4e --- /dev/null +++ b/VMware-OfflineSnapshots.ps1 @@ -0,0 +1,69 @@ +# in separate terminal +$MgmtHosts = @( + "itdvmbismgmt02.nd.gov", + "itdvmbismgmt03.nd.gov", + "itdvmmdnmgmt01.nd.gov", + "itdvmmdnmgmt02.nd.gov" +) + +Connect-ITDvCenter -Credential $PrvCred + +# Disable lockdown +ForEach($VMHostName in $MgmtHosts){ + (Get-VMHost $VMHostName | Get-View).ExitLockdownMode() +} + +Disconnect-ITDvCenter + +########## start from a fresh PowerShell session +# get credentials and connect +ForEach($VMHostName in $MgmtHosts){ + $Creds = $null + $Creds = Get-ITDPassword -Title $VMHostName -UserName root -Credential $PrvCred + Connect-VIServer -Server $VMHostName -Credential $Creds +} + +# verify direct host vi server connection +$global:DefaultVIServers + +# VM array +$VMarray = @( + "itdvmvc1.nd.gov", + "itdvmvc2.nd.gov", + "itdvmvra1.nd.gov", + "itdvmvra2.nd.gov", + "itdvmvrsmdn1.nd.gov", + "itdvmvrsmdn2.nd.gov", + "itdvmsrm1.nd.gov", + "itdvmsrm2.nd.gov" +) + +# get all VMs +$VMs = Get-VM -Name $VMarray | Sort-Object Name + +# shutdown VMs +$VMs | Get-VMGuest | Stop-VMGuest -Confirm:$false + +# wait for VMs to power off +Get-VM -Name $VMarray | Sort-Object Name + +# take snapshot of all VMs +$VMs | ForEach-Object {$_ | New-Snapshot -Name "Before-VR&SRM 9.0 upgrade"} + +# confirm all snapshots were taken +Get-VM -Name $VMarray | Get-Snapshot | Select VM,Name | sort-object VM + +# power on all VMs +Get-VM -Name $VMarray | Start-VM + + + +Disconnect-VIServer -Server * -Confirm:$false + +# disconnect all host direct connections +Disconnect-VIServer * -Confirm:$false + +# Enable Lockdown +ForEach($VMHostName in $MgmtHosts){ + (Get-VMHost $VMHostName | Get-View).EnterLockdownMode() +} \ No newline at end of file diff --git a/VMware-OrphanedFilesOnDatastore.ps1 b/VMware-OrphanedFilesOnDatastore.ps1 new file mode 100644 index 0000000..7b3f36e --- /dev/null +++ b/VMware-OrphanedFilesOnDatastore.ps1 @@ -0,0 +1,19 @@ +# datastore +$AllDatastores = Get-Datastore -Name *FS92* | sort-object Name + +$AllFiles = @() +ForEach ($Datastore in $AllDatastores) { + write-warning $Datastore.name + Set-Location $Datastore.DatastoreBrowserPath + + $expiredFolders = Get-ChildItem | ` + Where-Object { $_.Name -notlike "*.sf" -and $_.Name -notlike ".vSphere*" -and $_.Name -notlike ".dvs*" -and $_.Name -notlike ".naa*" -and $_.Name -ne 'vmkdump' -and $_.Name -ne 'syslog'} | ` + Where-Object LastWriteTime -LT ((Get-Date).AddDays(-30)) + + + ForEach ($folder in $expiredFolders) { + write-warning $folder.name + $AllFiles += Get-ChildItem -Path $Folder.FullName -Recurse + + } +} \ No newline at end of file diff --git a/VMware-PortGroupVMCount.ps1 b/VMware-PortGroupVMCount.ps1 new file mode 100644 index 0000000..f417f95 --- /dev/null +++ b/VMware-PortGroupVMCount.ps1 @@ -0,0 +1,43 @@ +$BISresult = @() +$PGs = Get-VirtualPortGroup -VirtualSwitch dvSwitch-PDC-Data +ForEach ($PG in $PGs) { + $obj = [PSCustomObject]@{ + Name = $PG.Name; + Count = ($PG | Get-VM).count + } + $BISresult += $obj +} + +$MDNresult = @() +$PGs = Get-VirtualPortGroup -VirtualSwitch dvSwitch-SDC-Data +ForEach ($PG in $PGs) { + $obj = [PSCustomObject]@{ + Name = $PG.Name; + Count = ($PG | Get-VM).count + } + $MDNresult += $obj +} + + + +$result = @() +$PGs = Get-VirtualPortGroup -VirtualSwitch dvSwitch-PDC-Data,dvSwitch-SDC-Data | Select -Unique Name +ForEach($PG in $PGs){ + $obj = [PSCustomObject]@{ + Name = $PG.Name; + VM_Count = (Get-VirtualPortGroup -Name $PG.Name | Get-VM).count + } +} + + +$result = [System.Collections.ArrayList]@() +$result2 = [System.Collections.ArrayList]@() +$BisPGs = Get-VDPortGroup -VDSwitch dvSwitch-PDC-Data +$MdnPGs = Get-VDPortGroup -VDSwitch dvSwitch-SDC-Data +ForEach($PG in $BisPGs){ + $obj = [PSCustomObject]@{ + Name = $PG.Name; + VM_Count = ($PG.ExtensionData.Vm.Count + ($MdnPGs | Where-Object Name -eq $PG.Name).ExtensionData.Vm.Count); + } + $null = $result2.Add($obj) +} \ No newline at end of file diff --git a/VMware-RemoveDatastores.ps1 b/VMware-RemoveDatastores.ps1 new file mode 100644 index 0000000..3a62f9b --- /dev/null +++ b/VMware-RemoveDatastores.ps1 @@ -0,0 +1,23 @@ +$Datastores = @" +VMTEST2_1_A9K_SYS +"@ +$Datastores = ConvertTo-Array -MultiLineString $Datastores + +foreach ($Datastore in $Datastores) { + $Datastore = Get-Datastore $Datastore + $VMhosts = $Datastore | Get-VMHost + $canonicalName = $Datastore.ExtensionData.Info.Vmfs.Extent[0].DiskName + $lunUuid = (Get-ScsiLun -VmHost $VMhosts | Where-Object { $_.CanonicalName -eq $canonicalName }).ExtensionData.Uuid | Select-Object -First 1 + $storSys = Get-View $VMhosts.ExtensionData.ConfigManager.StorageSystem + $device = $storSys.StorageDeviceInfo.ScsiLun | Where-Object { $_.CanonicalName -eq $canonicalName } + #unmount disk + if ($device.OperationalState[0] -eq 'ok') { + $storSys.UnmountVmfsVolume($Datastore.ExtensionData.Info.Vmfs.Uuid) + } + #detach disk + $storSys.DetachScsiLun($lunUuid) + #rescan hosts + foreach ($VMhost in $VMhosts) { + Get-VMHost $VMhost | Get-VMHostStorage -RescanAllHba -RescanVmfs + } +} \ No newline at end of file diff --git a/VMware-RunTCPDumpFromESX.txt b/VMware-RunTCPDumpFromESX.txt new file mode 100644 index 0000000..2ada280 --- /dev/null +++ b/VMware-RunTCPDumpFromESX.txt @@ -0,0 +1 @@ +tcpdump-uw -i vmk2 -s 1514 -C 200M -w /vmfs/volumes/VMALL1_008_FS92_TEMPL/test2.pcap \ No newline at end of file diff --git a/VMware-SQLVMsIndPerCheck.ps1 b/VMware-SQLVMsIndPerCheck.ps1 new file mode 100644 index 0000000..d4b8e9d --- /dev/null +++ b/VMware-SQLVMsIndPerCheck.ps1 @@ -0,0 +1,26 @@ +$SQLVMs = (Get-ITDVMwareSharePointVMGuestList | Where-Object { $_.LicensingRestrictions -like "*SQL*" -and $_.Status -ne "Deleted" }).Title | Sort-object + +$result = [System.Collections.ArrayList]@() + +ForEach ($SQLVM in $SQLVMs) { + $VM = $null + $Disks = $null + $PersistentDisks = $null + $IndPersistentDisks = $null + + $VM = Get-VM -Name $SQLVM | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" } + If ($VM) { + $Disks = $vm | Get-HardDisk + $PersistentDisks = $Disks | where-object Persistence -eq Persistent + $IndPersistentDisks = $Disks | Where-Object Persistence -eq IndependentPersistent + + $obj = [PSCustomObject]@{ + 'Name' = $VM.Name; + 'DisksPersistentCount' = @($PersistentDisks).count + 'DisksPersistentSizeGB' = ($PersistentDisks | measure-object -Sum CapacityGB).Sum + 'DisksIndPersistentCount' = @($IndPersistentDisks).count + 'DisksIndPersistentSizeGB' = ($IndPersistentDisks | measure-object -Sum CapacityGB).Sum + } + $null = $result.Add($obj) + } +} \ No newline at end of file diff --git a/VMware-ScratchLocations.ps1 b/VMware-ScratchLocations.ps1 new file mode 100644 index 0000000..1eb7323 --- /dev/null +++ b/VMware-ScratchLocations.ps1 @@ -0,0 +1,28 @@ +$AllHosts = Get-Datacenter Primary*, Secondary* | Get-Cluster | where-object {$_.Name -notlike "AVAYA*" -and $_.Name -notlike "TEL*"} | Sort-object Name | Get-VMHost +$result = @() +ForEach ($VMHost in $AllHosts) { + $Configured = $null + $Current = $null + $Configured = ($VMHost | Get-AdvancedSetting ScratchConfig.ConfiguredScratchLocation).Value; + $Current = ($VMHost | Get-AdvancedSetting ScratchConfig.CurrentScratchLocation).Value; + + + $obj = [PSCustomObject]@{ + Name = $VMHost.Name; + FS92 = If ($Configured -eq $Current) { $true }Else { $false }; + Configured = $Configured + Current = $Current + } + $result += $obj +} +<# +$HostsToReboot = $result | where-object FS92 -eq $False +ForEach($VMHost in $HostsToReboot){ + $VMHost | Set-VMHost -State "Maintenance" + #disable alarms + #restart host + #updateprofile + #remediateprofile + +} +#> \ No newline at end of file diff --git a/VMware-SnapshotsV3/prod/ITD.VMware.Snapshots.Prod.psm1 b/VMware-SnapshotsV3/prod/ITD.VMware.Snapshots.Prod.psm1 new file mode 100644 index 0000000..9b1b74a --- /dev/null +++ b/VMware-SnapshotsV3/prod/ITD.VMware.Snapshots.Prod.psm1 @@ -0,0 +1,484 @@ +function New-ITDVMwareVMSnapshotTaskV3Prd { + [CmdletBinding()] + Param ( + [int] + $Id, + + [PSCredential] + $SharePointCredential + ) + + begin { + $UrlContextInfo = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/contextinfo" + $InvokeRestMethodParams = @{ + Uri = $UrlContextInfo; + Method = "Post"; + UseBasicParsing = $true; + } + If ($SharePointCredential) { + $InvokeRestMethodParams += @{Credential = $SharePointCredential } + } + Else { + $InvokeRestMethodParams += @{UseDefaultCredentials = $true } + } + $RequestDigest = Invoke-RestMethod @InvokeRestMethodParams + $RequestDigest = $RequestDigest.GetContextWebInformation.FormDigestValue + + $UrlList = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')" + $InvokeRestMethodParams = @{ + Uri = $UrlList; + UseBasicParsing = $true; + } + If ($SharePointCredential) { $InvokeRestMethodParams += @{Credential = $SharePointCredential } } + Else { $InvokeRestMethodParams += @{UseDefaultCredentials = $true } } + $List = Invoke-RestMethod @InvokeRestMethodParams + $ListItemEntityTypeFullName = $list.entry.content.properties.ListItemEntityTypeFullName + + $UrlListItem = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')/items" + '?$top=10000' + '&$select=ID,Title,DateTime,Duration,Author/Name,Author/Title,Author/EMail,NotifyEmail&$expand=Author/Id' + $InvokeRestMethodParams = @{ + Uri = $UrlListItem; + Method = "Get"; + UseBasicParsing = $true; + Headers = @{ "Accept" = "application/json;odata=verbose" }; + } + If ($SharePointCredential) { $InvokeRestMethodParams += @{Credential = $SharePointCredential } } + Else { $InvokeRestMethodParams += @{UseDefaultCredentials = $true } } + $ListItems = ((Invoke-RestMethod @InvokeRestMethodParams) -creplace '"Id":', '"Idx":' | ConvertFrom-Json).d.results + + $header = @{ + "accept" = "application/json;odata=verbose" + "X-RequestDigest" = $RequestDigest + "IF-MATCH" = '*' + "X-HTTP-Method" = "MERGE" + } + } + + process { + $SPListItem = $ListItems | Where-object Id -eq $Id + $VMName = $SPListItem.Title + $SnapTime = [DateTime]$SPListItem.DateTime + $NotifyEmail = $SPListItem.Author.Email + If ($SPListItem.NotifyEmail) { $NotifyEmail = $NotifyEmail + ';' + $SPListItem.NotifyEmail } + + try { + $SnapName = "AutoSnap_" + $SPListItem.ID + $SnapExpireDateTime = $SnapTime.AddDays($SPListItem.Duration) + + If ($SnapExpireDateTime.DayOfWeek -eq "Saturday" -or $SnapExpireDateTime.DayOfWeek -eq "Sunday") { + $SnapExpireDateTime = $SnapExpireDateTime.AddDays(2) + } + $SnapDeleteDateTime = $SnapExpireDateTime.AddDays(2) + + $SnapDescription = [PSCustomObject]@{ + Number = $Id; + AutoExpire = $SnapExpireDateTime.ToLocalTime(); + AutoDelete = $SnapDeleteDateTime.ToLocalTime(); + } | ConvertTo-Json + + $snapMemory = $false + $snapQuiesce = $false + + Write-Warning $VMName + Write-Warning $SnapName + Write-Warning ("SharePoint: " + $SnapTime) + If ($SnapTime -lt (Get-Date)) { + $SnapTime = (Get-Date).AddSeconds(30) + } + Write-Warning ("PowerShell: " + $SnapTime) + + $VM = Get-VM -Name $VMName | where-object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" } + + If (@($VM).count -eq 2) { $VM = Get-VM -Name $VMName -Server ($global:DefaultVIServers | Sort-Object Name | Select-Object -First 1).Name } + $VIServer = $VM.Uid.split('@')[1].split(':')[0] + + # prep for SharePoint Record status update + $UrlItem = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')/items($Id)" + $InvokeRestMethodParams = @{ + Uri = $UrlItem; + Method = "Get"; + Headers = @{ "Accept" = "application/json;odata=verbose" } + UseBasicParsing = $true; + #Credential = $SharePointCredential + } + + If ($Credential) { $InvokeRestMethodParams += @{Credential = $SharePointCredential } } + Else { $InvokeRestMethodParams += @{UseDefaultCredentials = $true } } + + # actual creation of vCenter task + $si = Get-View ServiceInstance -Server $VIServer + $scheduledTaskManager = Get-View $si.Content.ScheduledTaskManager -Server $VIServer + + $spec = New-Object VMware.Vim.ScheduledTaskSpec + $spec.Name = $SnapName, $VMname -join '_' + $spec.Description = "$SnapDescription" + $spec.Enabled = $true + $spec.Notification = $NotifyEmail + + $spec.Scheduler = New-Object VMware.Vim.OnceTaskScheduler + $spec.Scheduler.runat = $SnapTime + + $spec.Action = New-Object VMware.Vim.MethodAction + $spec.Action.Name = "CreateSnapshot_Task" + + @($SnapName, $SnapDescription, $SnapMemory, $SnapQuiesce) | ForEach-Object { + $arg = New-Object VMware.Vim.MethodActionArgument + $arg.Value = $_ + $spec.Action.Argument += $arg + } + $scheduledTaskManager.CreateObjectScheduledTask($vm.ExtensionData.MoRef, $spec) + Start-Sleep -Seconds 3 + + } + catch { + write-error "vCenter Snapshot Scheduled Task Creation failed default message" + write-error $error[1] + Send-MailMessage -From "vmware@nd.gov" -To "zmeier@nd.gov" -Subject "VMware-Snapshot Schedule Failed Default Message - $SnapName" -Body "$SnapName`n$SnapDescription" -SmtpServer apprelay1.nd.gov + $Status = "Errored" + exit + } + + # update SharePoint record status + If ($Status -ne "Errored") { $Status = "Scheduled" } + [PSCustomObject]$SetRecord = @{ + "__metadata" = @{type = $ListItemEntityTypeFullName }; + Status = $Status; + } + $body = $SetRecord | ConvertTo-Json + $InvokeRestMethodParams = @{ + + Uri = $UrlItem; + Method = "Post"; + Body = $body; + ContentType = "application/json;odata=verbose"; + Headers = $header; + UseBasicParsing = $true; + } + If ($SharePointCredential) { $InvokeRestMethodParams += @{Credential = $SharePointCredential } } + Else { $InvokeRestMethodParams += @{UseDefaultCredentials = $true } } + Invoke-RestMethod @InvokeRestMethodParams + + $postParams = [PSCustomObject]@{ + AutomationName = "Infra-VMware"; + Action = 'Provisioning'; + Units = 5; + Platform = 'PowerShell-VMware-SnapshotNew'; + } + Invoke-RestMethod -Uri http://itdnettools.nd.gov/services/automation-tracking.py -Method POST -Body ($postParams | ConvertTo-Json) + + } + + end { + } +} + +function Update-ITDVMwareVMSnapshotTaskStatusV3Prd { + [CmdletBinding()] + Param ( + [int] + $Id, + + [PSCredential] + $SharePointCredential + ) + + If ($SharePointCredential) { + $SnapshotList = Get-ITDVMwareSharePointSnapshotRequestList -Credential $SharePointCredential + } + Else { + $SnapshotList = Get-ITDVMwareSharePointSnapshotRequestList + } + + If($Id) + { + $ListToUpdate = $SnapshotList | Where-Object { $_.Status -eq "Scheduled" -and $_.Id -eq $Id} + } + Else + { + $ListToUpdate = $SnapshotList | Where-Object { $_.Status -eq "Scheduled" } | Sort-Object DateTime + } + + ForEach ($SPRecord in $ListToUpdate) { + $VM = $null + $Taken = $null + $VMName = $null + $Duration = $null + $Id = $null + $VMSnapshot = $null + $Task = $null + + If ( (($SPRecord.DateTime) -as [datetime]).ToLocalTime() -lt (Get-Date) ) { + # If datetime has passed + $VMName = $SPRecord.Title + $VM = Get-VM -Name $VMName | where-object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" } + $Duration = $SPRecord.Duration + $Id = $SPRecord.Id + + switch ($Duration) { + { $Duration -ge 1 -and $Duration -le 7 } { + Write-Verbose "Duration = Snapshot" + #$VMSnapshots = $VM | Get-Snapshot | Where-Object Description -like "AutoSnap_$Id*" + $VMSnapshots = $VM | Get-Snapshot | Where-Object {($_.Description | ConvertFrom-Json).Number -eq $Id} + + If (@($VMSnapshots).count -eq 1) { + Write-Verbose "Exactly one snapshot match found" + $Taken = $true + $VMSnapshot = $VMSnapshots + #$Task = ((Get-View ((Get-View ScheduledTaskManager).ScheduledTask)).info | where-object Description -like "AutoSnap_$Id*") + $Task = (Get-View (Get-View ScheduledTaskManager).ScheduledTask).info | Where-Object Name -like ("AutoSnap_$id" + '_' + $VMName) + } + else { + if (@($VMSnapshots).count -gt 1) { + Write-Error "More than one snapshot match found, abort" + Exit + } + else { + $Taken = $false + Write-Verbose "Snapshot Id #$Id match not found on $VMName" + Write-Error "Snapshot $Id for $VMName not found." + } + } + } + { $Duration -ge 8 } { + Write-Verbose "Duration = Clone" + $VMClones = Get-VM | Where-Object Name -eq ($VMName + "_AutoClone_" + $Id) + + If (@($VMClones).count -eq 1) { + Write-Verbose "Exactly one clone match found" + $Taken = $true + $VMClone = $VMClones + #$Task = ((Get-View ((Get-View ScheduledTaskManager).ScheduledTask)).info | where-object Name -like "AutoClone_$Id*") + $Task = (Get-View (Get-View ScheduledTaskManager).ScheduledTask).info | Where-Object Name -like ("AutoClone_$id" + '_' + $VMName) + ############################## REVIEW + } + else { + if (@($VMClones).count -gt 1) { + Write-Error "More than one VM clone match found, abort" + Exit + } + else { + $Taken = $false + Write-Verbose "Clone Id #$Id match not found for $VMName" + Write-Error "Clone $Id for $VMName not found." + } + } + } + Default { + Write-Error "Duration less than zero." + } + } + + + Write-Verbose "Updating SharePoint fields named Status and SnapshotTaken" + $UrlContextInfo = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/contextinfo" + $InvokeRestMethodParams = @{ + Uri = $UrlContextInfo; + Method = "Post"; + UseBasicParsing = $true; + } + + If ($Credential) { $InvokeRestMethodParams += @{Credential = $SharePointCredential } } + Else { $InvokeRestMethodParams += @{UseDefaultCredentials = $true } } + $RequestDigest = Invoke-RestMethod @InvokeRestMethodParams + $RequestDigest = $RequestDigest.GetContextWebInformation.FormDigestValue + + $UrlList = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')" + $InvokeRestMethodParams = @{ + Uri = $UrlList; + UseBasicParsing = $true; + } + + If ($Credential) { $InvokeRestMethodParams += @{Credential = $SharePointCredential } } + Else { $InvokeRestMethodParams += @{UseDefaultCredentials = $true } } + $List = Invoke-RestMethod @InvokeRestMethodParams + $ListItemEntityTypeFullName = $list.entry.content.properties.ListItemEntityTypeFullName + + $UrlListItem = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')/items" + '?$top=10000' + $InvokeRestMethodParams = @{ + Uri = $UrlListItem; + Method = "Get"; + UseBasicParsing = $true; + Headers = @{ "Accept" = "application/json;odata=verbose" }; + } + If ($Credential) { $InvokeRestMethodParams += @{Credential = $SharePointCredential } } + Else { $InvokeRestMethodParams += @{UseDefaultCredentials = $true } } + $ListItems = ((Invoke-RestMethod @InvokeRestMethodParams) -creplace '"Id":', '"Idx":' | ConvertFrom-Json).d.results + + $header = @{ + "accept" = "application/json;odata=verbose" + "X-RequestDigest" = $RequestDigest + "IF-MATCH" = '*' + "X-HTTP-Method" = "MERGE" + } + + $UrlItem = "https://share.nd.gov/itd/computer-systems/distributed-systems/vmware/_api/lists/getbytitle('VMware-Snapshots')/items($Id)" + $InvokeRestMethodParams = @{ + Uri = $UrlItem; + Method = "Get"; + Headers = @{ "Accept" = "application/json;odata=verbose" } + UseBasicParsing = $true; + } + If ($Credential) { $InvokeRestMethodParams += @{Credential = $SharePointCredential } } + Else { $InvokeRestMethodParams += @{UseDefaultCredentials = $true } } + + [PSCustomObject]$SetRecord = @{ + "__metadata" = @{type = $ListItemEntityTypeFullName }; + #Status = 'Taken'; + Status = If ($Taken -eq $true) { 'Taken' } Else { 'Errored' }; + SnapshotTaken = $Task.PrevRunTime.ToLocalTime(); + AutoExpire = ($Task.Description | ConvertFrom-Json).AutoExpire + AutoDelete = ($Task.Description | ConvertFrom-Json).AutoDelete + } + + $body = $SetRecord | ConvertTo-Json + $InvokeRestMethodParams = @{ + + Uri = $UrlItem; + Method = "Post"; + Body = $body; + ContentType = "application/json;odata=verbose"; + Headers = $header; + UseBasicParsing = $true; + } + If ($Credential) { $InvokeRestMethodParams += @{Credential = $SharePointCredential } } + Else { $InvokeRestMethodParams += @{UseDefaultCredentials = $true } } + Invoke-RestMethod @InvokeRestMethodParams + } + } + + $postParams = [PSCustomObject]@{ + AutomationName = "Infra-VMware"; + Action = 'Provisioning'; + Units = 1; + Platform = 'PowerShell-VMware-SnapshotUpdateStatus'; + } + Invoke-RestMethod -Uri http://itdnettools.nd.gov/services/automation-tracking.py -Method POST -Body ($postParams | ConvertTo-Json) +} + +function New-ITDVMwareVMCloneTaskV3Prd { + [CmdletBinding()] + Param + ( + [Parameter(Mandatory = $true)] + [int[]] + $Id, + + [VMware.VimAutomation.ViCore.Impl.V1.DatastoreManagement.VmfsDatastoreImpl] + $Destination, + + [PSCredential] + $SharePointCredential, + + [PSCredential] + $vCenterCredential + ) + + begin { + $ConnectITDvCenterParams = @{ } + If ($vCenterCredential) { $ConnectITDvCenterParams += @{Credential = $vCenterCredential } } + Connect-ITDvCenter @ConnectITDvCenterParams + + $GetITDVMwareSharePointSnapshotRequestList = @{ } + If ($SharePointCredential) { $GetITDVMwareSharePointSnapshotRequestList += @{Credential = $SharePointCredential } } + $List = Get-ITDVMwareSharePointSnapshotRequestList @GetITDVMwareSharePointSnapshotRequestList + } + + process { + ForEach ($i in $ID) { + try { + $Request = $List | where-object ID -eq $i + $VMName = $Request.Title + $Duration = $Request.Duration + + $CloneTime = [DateTime]$Request.DateTime.ToLocalTime() + If ($CloneTime -lt (Get-Date)) { + $CloneTime = (Get-Date).AddSeconds(30) + } + + $CloneExpireDateTime = $CloneTime.AddDays($Duration) + $CloneDeleteDateTime = $CloneExpireDateTime.AddDays(2) + #$CloneDescription = ("AutoClone_" + $Request.ID + "`r" + "AutoExpire_$CloneExpireDateTime" + "`r" + "AutoDelete_$CloneDeleteDateTime") + $CloneDescription = [PSCustomObject]@{ + Number = $Id; + AutoExpire = $CloneExpireDateTime.ToLocalTime(); + AutoDelete = $CloneDeleteDateTime.ToLocalTime(); + } | ConvertTo-Json + $CloneVMName = ($VMName + "_AutoClone_" + $i) + + $VM = Get-VM -Name $VMName | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" } + + $VIServer = $VM.Uid.split('@')[1].split(':')[0] + $Folder = Get-Folder -Name "_Clone Request" -Server $VIServer + $Datastore = $VM | Get-Datastore + $DatastoreCluster = $VM | Get-DatastoreCluster + If (!($Destination)) { $Destination = Get-Datastore -Server $VIServer -Name *TEMPL* } + + # If DSCluster, clone to cluster + # doesn't fit go to TEMPL + # doesn't fit, error + # If dedicated lun, clone to TEMPL + # doesn't fit, error + + + If (($Destination.FreeSpaceGB * 0.90) -lt $VM.UsedSpaceGB) { + # Not enough free space, error + Write-Error ("Not enough free space on " + $Destination.Name) + } + else { + $ma = New-Object VMware.Vim.MethodAction + $ma.Argument = $null + $ma.Name = "CloneVM_Task" + $ar1 = New-Object VMware.Vim.MethodActionArgument + $ar1.Value = $vm.Folder.ExtensionData.MoRef + $ma.Argument += $ar1 + $ar2 = New-Object VMware.Vim.MethodActionArgument + $ar2.Value = $CloneVMName + $ma.Argument += $ar2 + $ar3 = New-Object VMware.Vim.MethodActionArgument + $vmSpec = New-Object VMware.Vim.VirtualMachineCloneSpec + $vmSpec.Location = New-Object VMware.Vim.VirtualMachineRelocateSpec + #$vmSpec.Location.Datastore = $vm.ExtensionData.Datastore[0] + #$vmSpec.Location.Datastore = (Get-Datastore -Name "*TEMPL*" -Server $VIServer).ExtensionData.MoRef + $vmSpec.Location.Datastore = (Get-Datastore -Name $Destination.Name -Server $VIServer).ExtensionData.MoRef + $vmSpec.Location.Pool = (Get-ResourcePool -VM $VM).ExtensionData.MoRef + $vmSpec.Location.Folder = $Folder.ExtensionData.MoRef + $vmSpec.Config = New-Object VMware.Vim.VirtualMachineConfigSpec + $vmSpec.Template = $false + $vmSpec.PowerOn = $false + $ar3.Value = $vmSpec + $ma.Argument += $ar3 + + <# + # Run at 21:00 every day + $dTScheduler = New-Object VMware.Vim.DailyTaskScheduler + $dTScheduler.Hour = 14 + $dTScheduler.Minute = 39 + $dTScheduler.Interval = 1 + #> + $dTScheduler = New-Object VMware.Vim.OnceTaskScheduler + $dTScheduler.runat = $CloneTime + + $tSpec = New-Object VMware.Vim.ScheduledTaskSpec + $tSpec.Action = $ma + $tSpec.Description = $CloneDescription + $tSpec.Enabled = $TRUE + $tSpec.Name = "AutoClone_" + $Request.ID + "_$VMName" + $tSpec.Notification = $Request.Author.EMail + $tSpec.Scheduler = $dTScheduler + + $stMgr = Get-View ScheduledTaskManager -Server $VIServer + $stMgr.CreateScheduledTask($vm.ExtensionData.MoRef, $tSpec) + } + } + catch { + write-error "vCenter Clone Scheduled Task Creation failed" + write-error $error[1] + #Send-MailMessage -From "vmware@nd.gov" -To "zmeier@nd.gov" -Subject "VMware-Snapshot Schedule Failed - $SnapName" -Body "$SnapName`n$SnapDescription" -SmtpServer apprelay1.nd.gov + $Status = "Errored" + exit + } + } + } + + end { + } +} \ No newline at end of file diff --git a/VMware-SnapshotsV3/prod/rb-VMware-NewVMSnapshotTask-prdV3.ps1 b/VMware-SnapshotsV3/prod/rb-VMware-NewVMSnapshotTask-prdV3.ps1 new file mode 100644 index 0000000..8e3999b --- /dev/null +++ b/VMware-SnapshotsV3/prod/rb-VMware-NewVMSnapshotTask-prdV3.ps1 @@ -0,0 +1,34 @@ +[CmdletBinding()] +param +( + [Parameter(Mandatory = $false)] + [object] $WebhookData +) + +If ($WebhookData) { + If ($WebhookData.RequestHeader.ITD -eq 'VRLEq2Yi7yzWW8fpKNCPB5gUcnHfr9sdhXC53y7gWf5BDtHAKpueFYU4L3N9ZxCWy63znqPGh3AJ2bn43uP7GjzfLcgqYLQRkirMXTKqtHssnNGBrew3gxXkr3mZA3NV7DszpR3kjiLgi3FpRPgUWus') { + Write-Verbose "Header has required data" + } + Else { + Write-Error "Header missing required data" + exit; + } + + $InputParams = (ConvertFrom-Json -InputObject $WebhookData.RequestBody) + $vCenterCredential = Get-AutomationPSCredential -Name 'VMware Auto' + $SharePointCredential = Get-AutomationPSCredential -Name 'SharePoint IaaS ReadWrite' + + Set-PowerCLIConfiguration -DefaultVIServerMode Multiple -ParticipateInCeip $false -Confirm:$false + + try { + + Connect-VIServer -Server itdvmvc1.nd.gov, itdvmvc2.nd.gov -Credential $vCenterCredential + New-ITDVMwareVMSnapshotTaskV3Prd -Id $InputParams.ID + Disconnect-VIServer -Server * -Confirm:$false -ErrorAction SilentlyContinue + } + catch { + } +} +Else { + Write-Error "Runbook must be started from webhook" +} \ No newline at end of file diff --git a/VMware-Stats.ps1 b/VMware-Stats.ps1 new file mode 100644 index 0000000..7d0b4ab --- /dev/null +++ b/VMware-Stats.ps1 @@ -0,0 +1,42 @@ +$stats = Get-Stat itdscmt1.nd.gov -Disk +$metrics = $stats | group-object MetricId + +$obj=[PSCustomObject]@{ + 'VMName' = 'itdscmt1.nd.gov'; + 'Usage' = [math]::round((($metrics | where-object Name -eq 'disk.usage.average').Group | Measure-Object -Average Value).Average,2); + 'Read' = [math]::round((($metrics | where-object Name -eq 'disk.read.average').Group | Measure-Object -Average Value).Average,2); + 'Write' = [math]::round((($metrics | where-object Name -eq 'disk.write.average').Group | Measure-Object -Average Value).Average,2); +} + + +$stats = Import-Csv "C:\users\zmeier\desktop\stats.csv" +$AllVMs = $stats | group-object Entity +$result = @() +ForEach($VM in $AllVMs) +{ + $VMstats = $VM.Group | group-object MetricId + $obj=[PSCustomObject]@{ + 'Name' = $VM.Name; + 'Usage' = [math]::round((($VMstats | where-object Name -eq 'disk.usage.average').Group | Measure-Object -Average Value).Average,2); + 'Read' = [math]::round((($VMstats | where-object Name -eq 'disk.read.average').Group | Measure-Object -Average Value).Average,2); + 'Write' = [math]::round((($VMstats | where-object Name -eq 'disk.write.average').Group | Measure-Object -Average Value).Average,2); + } + $result += $obj +} + + +#$DHSVMs = Get-DatastoreCluster *linux*V5K* | Get-VM itddhsdevblda01*,itddhsdevbata01*,itddhsdevcmdb01*,itddhsdevwasw02*,itddhsdevesba01.nd.gov* #| #where-object Name -like "itddhs*" | sort-object UsedSpaceGB +$VMs = Get-DatastoreCluster *V5K* | Get-VM +$result = @() +ForEach($VM in $VMs) +{ + $vmstats = $VM | Get-stat -Disk -Realtime + #VM | select Name,@{n='usage';e={[math]::round(($_ | where-object PowerState -eq PoweredOn | Get-Stat -disk -realtime | where-object metricid -eq 'disk.usage.average' | measure-object -average Value).Average,2)}} + + $obj =[PSCustomObject]@{ + Usage = [math]::round(($VMstats | where-object metricid -eq 'disk.usage.average' | measure-object -average value),2) ; + Read = [math]::round(($VMstats | where-object metricid -eq 'disk.usage.average' | measure-object -average value),2) ; + Write = [math]::round(($VMstats | where-object metricid -eq 'disk.usage.average' | measure-object -average value),2) ; + } + $result += $obj +} \ No newline at end of file diff --git a/VMware-TCPDump.ps1 b/VMware-TCPDump.ps1 new file mode 100644 index 0000000..5229086 --- /dev/null +++ b/VMware-TCPDump.ps1 @@ -0,0 +1,2 @@ + +tcpdump-uw -i vmk2 -s 1514 -C 200M -w /vmfs/volumes/VMALL2_009_FS92_TEMPL/tcpdump/test1.pcap \ No newline at end of file diff --git a/VMware-TPM.ps1 b/VMware-TPM.ps1 new file mode 100644 index 0000000..e228e48 --- /dev/null +++ b/VMware-TPM.ps1 @@ -0,0 +1,20 @@ +$Result = [System.Collections.ArrayList]@() +$VMHosts = Get-VMHost +ForEach ($VMHost in $VMHostNames) { + $EsxCli = Get-EsxCli -VMHost $VMHost -V2 + $Settings = $EsxCli.system.settings.encryption.get.invoke() + If ($Settings.Mode -eq "TPM") { + $list = $EsxCli.system.settings.encryption.recovery.list.invoke() + $obj = [PSCustomObject]@{ + 'Name' = $VMHost + 'Key' = $list.Key + 'RecoveryId' = $list.RecoveryId + } + + $null = $Result.Add($obj) + } + else { + $obj = $null + $list = $null + } +} \ No newline at end of file diff --git a/VMware-TemplateUpdates.ps1 b/VMware-TemplateUpdates.ps1 new file mode 100644 index 0000000..02b7af0 --- /dev/null +++ b/VMware-TemplateUpdates.ps1 @@ -0,0 +1,54 @@ +Connect-ITDvCenter -Credential $PrvCred +$GuestCredential = Get-Secret -Name GuestCredential +$AllNames = "Windows Server 2019*" +#$AllNames = "zm2019" +Get-Template -Name $AllNames | Where-Object {$_.Name -notlike "*(Base)*"} | Set-Template -ToVM + +#Get-VM -Name $AllNames | New-Snapshot -Name "0_Before Testing" + +$VMs = Get-VM -Name $AllNames -server itdvmvc1.nd.gov | Where-Object PowerState -ne "PoweredOn" | Start-VM +Get-VM -Name $AllNames | Wait-Tools | Out-Null +Write-Warning "Tools started" + +while ((Get-VM -Name $AllNames).ExtensionData.Guest.GuestOperationsReady -contains $false){start-sleep -seconds 5} +Write-Warning "Guest Operations Ready" + +$PowerCliContext = Get-PowerCLIContext +Write-Warning "Wait for 3 minutes" +start-sleep -seconds 180 +Write-Warning "Wait complete" + +Get-VM -Name $AllNames | ForEach-Object -Parallel { + Use-PowerCLIContext -PowerCLIContext $using:PowerCliContext -SkipImportModuleChecks + Get-VM -Name $_.Name | Wait-Tools + $WUfunc = { + Write-Host "Search for relevant updates" + + $Updates = New-Object -ComObject Microsoft.Update.UpdateColl + $Searcher = New-Object -ComObject Microsoft.Update.Searcher + $Session = New-Object -ComObject Microsoft.Update.Session + $Criteria = "IsInstalled=0 and Type='Software' and IsAssigned=1" + #IsAssigned Finds updates that are intended for deployment by Automatic Updates. This stops Preview updates for Windows and .NET + # https://docs.microsoft.com/en-us/windows/win32/api/wuapi/nf-wuapi-iupdatesearcher-search + $Result = $Searcher.Search($Criteria) + $Updates = $Result.Updates + + $Updates | Sort-Object Title | Select-Object Title + + $Downloader = $Session.CreateUpdateDownloader() + $Downloader.Updates = $Updates + $Downloader.Download() + + $Installer = New-Object -ComObject Microsoft.Update.Installer + $Installer.Updates = $Updates + $Installer.Install() + #> + } + + Get-VM -Name $_.Name | Invoke-VMScript -GuestCredential $using:GuestCredential -ScriptType PowerShell -ScriptText $WUfunc + Write-Warning ($_.Name + " updates completed, needs reboot...") +} + +Get-VM -Name $_.Name | Restart-VMGuest -Confirm:$false | Out-Null + +Get-VM -Name $AllNames | Set-VM -ToTemplate \ No newline at end of file diff --git a/VMware-VMPowerOffInfo.ps1 b/VMware-VMPowerOffInfo.ps1 new file mode 100644 index 0000000..0b109fb --- /dev/null +++ b/VMware-VMPowerOffInfo.ps1 @@ -0,0 +1,39 @@ +$Report = @() + +$VMs = Get-VM | Where {$_.PowerState -eq "PoweredOff"} + +$Datastores = Get-Datastore | Select Name, Id + +$PowerOffEvents = Get-VIEvent -Entity $VMs -MaxSamples ([int]::MaxValue) | where {$_ -is [VMware.Vim.VmPoweredOffEvent]} | Group-Object -Property {$_.Vm.Name} + +foreach ($VM in $VMs) { + + $lastPO = ($PowerOffEvents | Where { $_.Group[0].Vm.Vm -eq $VM.Id }).Group | Sort-Object -Property CreatedTime -Descending | Select -First 1 + + $row = "" | select VMName,Powerstate,OS,Host,Cluster,Datastore,NumCPU,MemMb,DiskGb,PoweredOffTime,PoweredOffBy + + $row.VMName = $vm.Name + + $row.Powerstate = $vm.Powerstate + + $row.OS = $vm.Guest.OSFullName + + $row.Host = $vm.VMHost.name + + $row.Cluster = $vm.VMHost.Parent.Name + + $row.Datastore = $Datastores | Where{$_.Id -eq ($vm.DatastoreIdList | select -First 1)} | Select -ExpandProperty Name + + $row.NumCPU = $vm.NumCPU + + $row.MemMb = $vm.MemoryMB + + $row.DiskGb = Get-HardDisk -VM $vm | Measure-Object -Property CapacityGB -Sum | select -ExpandProperty Sum + + $row.PoweredOffTime = $lastPO.CreatedTime + + $row.PoweredOffBy = $lastPO.UserName + + $report += $row + +} \ No newline at end of file diff --git a/VMware-VMToolsProductLocker.ps1 b/VMware-VMToolsProductLocker.ps1 new file mode 100644 index 0000000..d986ab4 --- /dev/null +++ b/VMware-VMToolsProductLocker.ps1 @@ -0,0 +1,28 @@ +$VMHosts = Get-VMHost +#$VMHosts = Get-VMHost itdmdnvm-ps01.nd.gov +$Result = [System.Collections.ArrayList]@() + +ForEach($VMHost in $VMHosts) +{ + $Datacenter = $VMHost | Get-Datacenter + + switch ($Datacenter.Name) { + 'Secondary Datacenter' {$FullPath = '/vmfs/volumes/VMTEMPL2_253_A9K_MISC/VMwareTools'} # 5b71994c-91a540f5-2799-5cb901c7ebb0 + 'Primary Datacenter' {$FullPath = '/vmfs/volumes/VMTEMPL1_252_A9K_MISC/VMwareTools'} # 5b72f9fe-6fe879bb-2c19-6cc217314910 + 'DCN Datacenter' {$FullPath = '/vmfs/volumes/VMDCN1_20_V5K/VMwareTools'} # 5a737d2f-b45bb27d-7f74-e0071befea78 + 'DES Datacenter' {$FullPath = '/vmfs/volumes/VMDES1_10_V3700/VMwareTools'} # 556f4727-d3b6d2cd-3b9c-8cdcd4add10c + Default {} + } + + $OldToolsSetting = Get-AdvancedSetting -Entity $VMHost -Name UserVars.ProductLockerLocation + Write-Warning ("PreviousValue: " + ($OldToolsSetting | select Entity,Name,Value)) + #$OldToolsSetting | Set-AdvancedSetting -Value $FullPath -Confirm:$false + $obj=[PSCustomObject]@{ + 'Entity' = $VMhost.Name; + 'Value' = $OldToolsSetting.Value; + } + + $null = $Result.Add($obj) +} + +# host reboot required to take effect \ No newline at end of file diff --git a/VMware-VMToolsUpgrade.ps1 b/VMware-VMToolsUpgrade.ps1 new file mode 100644 index 0000000..bed18d7 --- /dev/null +++ b/VMware-VMToolsUpgrade.ps1 @@ -0,0 +1,52 @@ +<#$servers = (import-csv 'D:\State of North Dakota\-Tm-ITD-Virtualization - Documents\VMware\VMwareTools-Test.csv') +$servers = import-csv C:\users\zmeier\desktop\servers-test.csv +#$VMs = Get-VM | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" } | where-object Name -eq itdzmtest222 +$VMs = Get-VM | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" } | where-object Name -match $servers +$VMs = [System.Collections.ArrayList]@() +ForEach($server in $servers[101..250]){ + #Get-VM -Name asdf | Update-Tools -RunASync -NoReboot +} +$VMs = get-vm $servers.computername +# Record Before Stats and Execute +get-vm $servers.computername | select Name,@{n='ToolsVersion';e={$_.Guest.ToolsVersion}} -ov Before + +#$VMs | Update-Tools -NoReboot -RunASync + + + +# Status after +#Get-VM -Name $VMs.ComputerName | select Name,@{n='ToolsVersion';e={$_.Guest.ToolsVersion}} -ov After + +Get-VM -Name $servers.computername | Where-Object PowerState -eq PoweredOn | where-object {$_.Guest.ToolsVersion -ne "12.0.0"} | select Name,@{n='ToolsVersion';e={$_.Guest.ToolsVersion}} -ov Left +Get-VM -Name $servers.computername | Where-Object PowerState -eq PoweredOn | where-object {$_.Guest.ToolsVersion -ne "12.0.0"} +#Get-VM -Name $servers.computername | where-object {$_.Guest.ToolsVersion -ne "12.0.0"} | Update-Tools -RunASync + +#Get-VM itdernappu01.nd.gov | Update-Tools -RunASync +#> + +# 2022/03/20 +$After = Get-VM | Where-Object { $_.PowerState -eq "PoweredOn" -and $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" } | select Name,@{n='ToolsVersion';e={$_.Guest.ToolsVersion}} + +<#$servers = @" +itdernappu01.nd.gov +"@ +$servers = ConvertTo-Array -MultiLineString $servers #> + +# Reboot VM +<#ForEach($server in $servers){ + #Get-VM $server | Where-Object { $_.PowerState -eq "PoweredOn" -and $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" } | Restart-VMGuest +}#> + +Get-VM $servers | Where-Object { $_.PowerState -eq "PoweredOn" -and $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" } | select Name,PowerState,@{n='ToolsVersion';e={$_.Guest.ToolsVersion}},@{n='ToolsState';e={$_.Guest.State}} | sort-object Name -ov Latest + +# Install VMware Tools, and reboot +ForEach($server in $servers){ + #Get-VM $server | Where-Object { $_.PowerState -eq "PoweredOn" -and $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" }| Where-Object { $_.PowerState -eq "PoweredOn" -and $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" } | Update-Tools -RunAsync + start-sleep -seconds 1 +} + +Get-VM $servers | Where-Object { $_.PowerState -eq "PoweredOn" -and $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" } | select Name,PowerState,@{n='ToolsVersion';e={$_.Guest.ToolsVersion}},@{n='ToolsState';e={$_.Guest.State}} | where-object ToolsVersion -ne "12.0.0" | sort-object Name -ov Left +$Left.count + +Get-VM | Where-Object { $_.GuestId -like "*windows*" -and $_.PowerState -eq "PoweredOn" -and $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" } | select Name,PowerState,@{n='ToolsVersion';e={$_.Guest.ToolsVersion}},@{n='ToolsState';e={$_.Guest.State}} | where-object ToolsVersion -ne "12.0.0" | sort-object Name -ov AllLeft +$AllLeft.count \ No newline at end of file diff --git a/VMware-VMToolsUpgradeAutoOnReboot.ps1 b/VMware-VMToolsUpgradeAutoOnReboot.ps1 new file mode 100644 index 0000000..e7a3315 --- /dev/null +++ b/VMware-VMToolsUpgradeAutoOnReboot.ps1 @@ -0,0 +1,33 @@ +# Get Tools Upgrade option +$AllVMs = Get-VM | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" -and $_.ExtensionData.Guest.GuestId -like "windows*" } +$AllVMsWindows = $AllVMs | Where-Object {$_.Guest.OSFullName -like "*Windows*"} +$Result = [System.Collections.ArrayList]@() +Foreach($VM in $AllVMsWindows){ + $obj=[PSCustomObject]@{ + Name = $VM.Name; + ToolsVersion = $VM.ExtensionData.Config.Tools.ToolsVersion; + ToolsUpgradePolicy = $VM.ExtensionData.Config.Tools.ToolsUpgradePolicy + } + $null = $Result.Add($obj) +} +$Result + +# set all Windows VMs to manual VMware Tools upgrade +$VMs = Get-VM | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" -and $_.ExtensionData.Guest.GuestId -like "windows*"} +Foreach ($v in $VMs) { + $vm = $v | Get-View + $vmConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec + $vmConfigSpec.Tools = New-Object VMware.Vim.ToolsConfigInfo + $vmConfigSpec.Tools.ToolsUpgradePolicy = "manual" + $vm.ReconfigVM($vmConfigSpec) +} + +# set all VMs to upgradeAtPowerCycle VMware Tools +$VMs = Get-VM | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" -and $_.ExtensionData.Guest.GuestId -like "windows*" -and $_.ExtensionData.config.tools.ToolsUpgradePolicy -ne "UpgradeAtPowerCycle"} +Foreach ($v in $VMs) { + $vm = $v | Get-View + $vmConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec + $vmConfigSpec.Tools = New-Object VMware.Vim.ToolsConfigInfo + $vmConfigSpec.Tools.ToolsUpgradePolicy = "UpgradeAtPowerCycle" + $vm.ReconfigVM($vmConfigSpec) +} \ No newline at end of file diff --git a/VMware-vVolCount.ps1 b/VMware-vVolCount.ps1 new file mode 100644 index 0000000..d1e64d7 --- /dev/null +++ b/VMware-vVolCount.ps1 @@ -0,0 +1,8 @@ +$BisDatastores = Get-Datacenter Primary* | Get-Datastore | where-object {$_.Name -notlike "*A9K_R*" -and $_.Name -notlike "*SYS*" -and $_.Name -notlike "*V5K*" -and $_.Name -notlike "*local*"} +$BisVMs = $BisDatastores | Get-VM | where-object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" } +$BisGroup = $BisVMs | select Name,@{n='vVols';e={($_ | Get-HardDisk).count + 2}} | group-object vVols + + +$MdnDatastores = Get-Datacenter Secondary* | Get-Datastore | where-object {$_.Name -notlike "*A9K_R*" -and $_.Name -notlike "*SYS*" -and $_.Name -notlike "*V5K*" -and $_.Name -notlike "*local*"} +$MdnVMs = $MdnDatastores | Get-VM | where-object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" } +$MdnGroup = $MdnVMs | select Name,@{n='vVols';e={($_ | Get-HardDisk).count + 2}} | group-object vVols \ No newline at end of file diff --git a/VMware-vVolsForTest.ps1 b/VMware-vVolsForTest.ps1 new file mode 100644 index 0000000..e9f29f6 --- /dev/null +++ b/VMware-vVolsForTest.ps1 @@ -0,0 +1,37 @@ +$AllVMs = Get-VM | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" } +$VMs = $AllVMs | select Name, ` + @{n = 'ProvisionedSpaceGBr'; e = { [math]::round($_.ProvisionedSpaceGB, 2) } }, ` + @{n = 'UsedSpaceGBr'; e = { [math]::round($_.UsedSpaceGB) } } + +$BisResult = [System.Collections.ArrayList]@() +$Clusters = Get-Datacenter Primary* | Get-Cluster +ForEach ($Cluster in $Clusters) { + $VMs = $Cluster | Get-VM -Tag "Test" | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" } + $Sum = $VMs | Measure-Object -Sum UsedSpaceGB, ProvisionedSpaceGB + + $obj = [PSCustomObject]@{ + Name = $Cluster.Name; + UsedSpaceGB = [math]::round(($Sum | Where-Object Property -eq UsedSpaceGB).Sum, 2) + ProvisionedSpaceGB = [math]::round(($Sum | Where-Object Property -eq ProvisionedSpaceGB).Sum, 2) + } + + $BisResult.Add($obj) +} + +$MdnResult = [System.Collections.ArrayList]@() +$Clusters = Get-Datacenter Secondary* | Get-Cluster +ForEach ($Cluster in $Clusters) { + $VMs = $Cluster | Get-VM -Tag "Test" | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" } + $Sum = $VMs | Measure-Object -Sum UsedSpaceGB, ProvisionedSpaceGB + + $obj = [PSCustomObject]@{ + Name = $Cluster.Name; + UsedSpaceGB = [math]::round(($Sum | Where-Object Property -eq UsedSpaceGB).Sum, 2) + ProvisionedSpaceGB = [math]::round(($Sum | Where-Object Property -eq ProvisionedSpaceGB).Sum, 2) + } + + $MdnResult.Add($obj) +} + +$MdnTotal = $MdnResult | Measure-Object -Sum UsedSpaceGB, ProvisionedSpaceGB +$BisTotal = $BisResult | Measure-Object -Sum UsedSpaceGB, ProvisionedSpaceGB \ No newline at end of file diff --git a/WSL.ps1 b/WSL.ps1 new file mode 100644 index 0000000..cc7a539 --- /dev/null +++ b/WSL.ps1 @@ -0,0 +1,13 @@ +<# default user /etc/wsl.conf +[user] +default = zmeier +#> + +Find-Module Microsoft.PowerShell.Secret* +Find-Module Microsoft.PowerShell.Secret* | Install-Module -Scope CurrentUser +Register-SecretVault -Name SecretStore -Module Microsoft.PowerShell.SecretStore -DefaultVault +Set-Secret -Name PrvCred -Secret (Get-Credential) +# enter credential object to save in vault +# then enter password to secure the vault +Get-SecretStoreConfiguration # view vault settings +Set-SecretStoreConfiguration -Interaction None # always allow access to current user \ No newline at end of file diff --git a/Windows-ESUDiscovery.ps1 b/Windows-ESUDiscovery.ps1 new file mode 100644 index 0000000..0bcab89 --- /dev/null +++ b/Windows-ESUDiscovery.ps1 @@ -0,0 +1,97 @@ +#MAK & ESU discovery v2 + +$Esu1Bool = $false +$Esu2Bool = $false +$MakBool = $false + +$OS = (Get-WMIObject Win32_OperatingSystem).Caption +Write-Verbose $OS + +switch ($OS) { + 'Microsoft Windows Server 2008 R2 Datacenter ' { + write-verbose "switch datacenter edition" + $MakId = '4ae528f4-05c3-446e-90ea-a4fbd460b83a' + $MakKey = 'MF2F8-YGGFX-6MKDF-PCM29-7BYDG' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' #activationid + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + } + 'Microsoft Windows Server 2008 R2 Enterprise ' { + write-verbose "switch enterprise edition" + $MakId = '6a4bd364-4b60-4856-a727-efb59d94348e' + $MakKey = '3YY4J-742QP-GPKP9-G2R6W-K6DDM' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + } + 'Microsoft Windows Server 2008 R2 Standard ' { + write-verbose "switch standard edition" + $MakId = '' + $MakKey = '3YY4J-742QP-GPKP9-G2R6W-K6DDM' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + } + 'Microsoft Windows 7 Enterprise ' { + write-verbose "switch Win7 enterprise edition" + $MakId = '9abf5984-9c16-46f2-ad1e-7fe15931a8dd' + $MakKey = 'PRV3H-98HJK-6KKBF-RHYTM-JWCRV' + $Esu1Id = '77db037b-95c3-48d7-a3ab-a9c6d41093e0' + $Esu1Key = 'MJCJ8-24DFX-VGK6H-XYBQ7-F6PR8' + $Esu2Id = '0e00c25d-8795-4fb7-9572-3803d91b6880' + $Esu2Key = 'WX34W-WG8MH-TWWCV-PXK96-RDMTJ' + } + 'Microsoft® Windows Server® 2008 Standard ' { + write-verbose "switch 08 Standard" + $MakId = 'ad2542d4-9154-4c6d-8a44-30f11ee96989' + $MakKey = 'GQK9D-CT4WQ-9KJ87-FKMT8-MR73Q' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + } + 'Microsoft® Windows Server® 2008 Enterprise ' { + write-verbose "switch 08 Enterprise" + $MakId = 'bb1d27c4-959d-4f82-b0fd-c02a7be54732' + $MakKey = 'GQK9D-CT4WQ-9KJ87-FKMT8-MR73Q' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + } +} + +$software = Get-WMIObject -Class SoftwareLicensingProduct + +$EsuYear1 = $software | Where-Object { $_.Id -eq $Esu1Id } +If ($EsuYear1) { + If ($EsuYear1.LicenseStatus -eq '1') { + $Esu1Bool = $true + } +} + +$EsuYear2 = $software | Where-Object { $_.Id -eq $Esu2Id } +If ($EsuYear2) { + If ($EsuYear2.LicenseStatus -eq '1') { + $Esu2Bool = $true + } +} + +$Mak = $software | where-object { $_.Id -eq $MakId } +If ($Mak) { + If ($Mak.LicenseStatus -eq 1) { + $MakBool = $true + } +} + +If ($Esu1bool -eq $true -and $Esu2Bool -eq $true -and $Makbool -eq $true) { + $compliant = $true +} +else { + $compliant = $false +} + +$compliant \ No newline at end of file diff --git a/Windows-ESUDiscovery2012.ps1 b/Windows-ESUDiscovery2012.ps1 new file mode 100644 index 0000000..4b21517 --- /dev/null +++ b/Windows-ESUDiscovery2012.ps1 @@ -0,0 +1,83 @@ +#MAK & ESU discovery v3 + +$Esu1Bool = $false +$Esu2Bool = $false +$Esu3Bool = $false +$MakBool = $false + +$OS = (Get-WmiObject Win32_OperatingSystem).Caption +Write-Verbose $OS + +$Esu1Key = '4RPR3-NRF26-9CTKB-7GRXQ-GF72Q' +$Esu2Key = $null +$Esu3Key = $null + +# activation IDs found here +# https://techcommunity.microsoft.com/t5/windows-it-pro-blog/windows-server-2012-r2-extended-security-updates/ba-p/3976610 +$Esu1Id = 'c0a2ea62-12ad-435b-ab4f-c9bfab48dbc4' +$Esu2Id = 'e3e2690b-931c-4c80-b1ff-dffba8a81988' +$Esu3Id = '55b1dd2d-2209-4ea0-a805-06298bad25b3' + +$software = Get-WmiObject -Class SoftwareLicensingProduct + +If ($Esu1Key) { + Write-Verbose -Message "Esu1Key found, checking LicenseStatus" + $EsuYear1 = $software | Where-Object { $_.Id -eq $Esu1Id } + If ($EsuYear1) { + If ($EsuYear1.LicenseStatus -eq '1') { + $Esu1Bool = $true + } + } +} + +If ($Esu2Key) { + Write-Verbose -Message "Esu2Key found, checking LicenseStatus" + $EsuYear2 = $software | Where-Object { $_.Id -eq $Esu2Id } + If ($EsuYear2) { + If ($EsuYear2.LicenseStatus -eq '1') { + $Esu2Bool = $true + } + } +} + +If ($Esu3Key) { + Write-Verbose -Message "Esu3Key found, checking LicenseStatus" + $EsuYear3 = $software | Where-Object { $_.Id -eq $Esu3Id } + If ($EsuYear3) { + If ($EsuYear3.LicenseStatus -eq '1') { + $Esu3Bool = $true + } + } +} + +# Year 1 only +If ($Esu1Key -and $null -eq $Esu2Key -and $null -eq $Esu3Key) { + If ($Esu1Bool -eq $true) { + $compliant = $true + } + else { + $compliant = $false + } +} + +# Year 1 & 2 +If ($Esu1Key -and $Esu2Key -and $null -eq $Esu3Key) { + If ($Esu1Bool -eq $true -and $Esu2Bool -eq $true) { + $compliant = $true + } + else { + $compliant = $false + } +} + +# Year 1 & 2 & 3 +If ($Esu1Key -and $Esu2Key -and $Esu3Key ) { + If ($Esu1Bool -eq $true -and $Esu2Bool -eq $true -and $Esu3Bool -eq $true) { + $compliant = $true + } + else { + $compliant = $false + } +} + +$compliant \ No newline at end of file diff --git a/Windows-ESURemediation.ps1 b/Windows-ESURemediation.ps1 new file mode 100644 index 0000000..657031b --- /dev/null +++ b/Windows-ESURemediation.ps1 @@ -0,0 +1,68 @@ +#MAK & ESU remediation v2 + +$OS = (Get-WMIObject Win32_OperatingSystem).Caption +write-verbose $OS + +switch ($OS) { + 'Microsoft Windows Server 2008 R2 Datacenter ' { + write-verbose "switch datacenter edition" + $MakId = '4ae528f4-05c3-446e-90ea-a4fbd460b83a' + $MakKey = 'MF2F8-YGGFX-6MKDF-PCM29-7BYDG' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' #activationid + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + } + 'Microsoft Windows Server 2008 R2 Enterprise ' { + write-verbose "switch enterprise edition" + $MakId = '6a4bd364-4b60-4856-a727-efb59d94348e' + $MakKey = '3YY4J-742QP-GPKP9-G2R6W-K6DDM' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + } + 'Microsoft Windows Server 2008 R2 Standard ' { + write-verbose "switch standard edition" + $MakId = '' + $MakKey = '3YY4J-742QP-GPKP9-G2R6W-K6DDM' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + } + 'Microsoft Windows 7 Enterprise ' { + write-verbose "switch Win7 enterprise edition" + $MakId = '9abf5984-9c16-46f2-ad1e-7fe15931a8dd' + $MakKey = 'PRV3H-98HJK-6KKBF-RHYTM-JWCRV' + $Esu1Id = '77db037b-95c3-48d7-a3ab-a9c6d41093e0' + $Esu1Key = 'MJCJ8-24DFX-VGK6H-XYBQ7-F6PR8' + $Esu2Id = '0e00c25d-8795-4fb7-9572-3803d91b6880' + $Esu2Key = 'WX34W-WG8MH-TWWCV-PXK96-RDMTJ' + } + 'Microsoft® Windows Server® 2008 Standard ' { + write-verbose "switch 08 Standard" + $MakId = 'ad2542d4-9154-4c6d-8a44-30f11ee96989' + $MakKey = 'GQK9D-CT4WQ-9KJ87-FKMT8-MR73Q' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + } + 'Microsoft® Windows Server® 2008 Enterprise ' { + write-verbose "switch 08 Enterprise" + $MakId = 'bb1d27c4-959d-4f82-b0fd-c02a7be54732' + $MakKey = 'GQK9D-CT4WQ-9KJ87-FKMT8-MR73Q' + $Esu1Id = '553673ed-6ddf-419c-a153-b760283472fd' + $Esu1Key = 'MMFTT-7FBRY-W9QYW-37FMB-TRPJK' + $Esu2Id = '04fa0286-fa74-401e-bbe9-fbfbb158010d' + $Esu2Key = '6P3TQ-J2C3Y-VK2TD-8P648-Y3TF6' + } +} + +cscript C:\Windows\System32\slmgr.vbs -ipk $MakKey +cscript C:\Windows\System32\slmgr.vbs -ato $MakId +cscript C:\Windows\System32\slmgr.vbs -ipk $Esu1Key +cscript C:\Windows\System32\slmgr.vbs -ato $Esu1Id +cscript C:\Windows\System32\slmgr.vbs -ipk $Esu2Key +cscript C:\Windows\System32\slmgr.vbs -ato $Esu2Id \ No newline at end of file diff --git a/Windows-ESURemediation2012.ps1 b/Windows-ESURemediation2012.ps1 new file mode 100644 index 0000000..102b753 --- /dev/null +++ b/Windows-ESURemediation2012.ps1 @@ -0,0 +1,31 @@ +#MAK & ESU remediation v3 + +$OS = (Get-WmiObject Win32_OperatingSystem).Caption +Write-Verbose $OS + +$Esu1Key = '4RPR3-NRF26-9CTKB-7GRXQ-GF72Q' +$Esu2Key = $null +$Esu3Key = $null + +# activation IDs found here +# https://techcommunity.microsoft.com/t5/windows-it-pro-blog/windows-server-2012-r2-extended-security-updates/ba-p/3976610 +$Esu1Id = 'c0a2ea62-12ad-435b-ab4f-c9bfab48dbc4' +$Esu2Id = 'e3e2690b-931c-4c80-b1ff-dffba8a81988' +$Esu3Id = '55b1dd2d-2209-4ea0-a805-06298bad25b3' + + +If ($Esu1Key) { + Write-Verbose -Message "Esu1Key found, activating" + cscript C:\Windows\System32\slmgr.vbs -ipk $Esu1Key + cscript C:\Windows\System32\slmgr.vbs -ato $Esu1Id +} +If ($Esu2Key) { + Write-Verbose -Message "Esu2Key found, activating" + cscript C:\Windows\System32\slmgr.vbs -ipk $Esu2Key + cscript C:\Windows\System32\slmgr.vbs -ato $Esu2Id +} +If ($Esu3Key) { + Write-Verbose -Message "Esu3Key found, activating" + cscript C:\Windows\System32\slmgr.vbs -ipk $Esu3Key + cscript C:\Windows\System32\slmgr.vbs -ato $Esu3Id +} \ No newline at end of file diff --git a/Windows-InstallAllMUUpdates.ps1 b/Windows-InstallAllMUUpdates.ps1 new file mode 100644 index 0000000..20e610b --- /dev/null +++ b/Windows-InstallAllMUUpdates.ps1 @@ -0,0 +1,35 @@ +Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredential -ScriptType PowerShell -ScriptText { + <#Write-Progress -Activity "Windows Update" -Status "Configure Auto Update Settings" + Write-Verbose "Configure Windows Updates to never check for updates" + $WUSettings = (New-Object -ComObject "Microsoft.Update.AutoUpdate").Settings + $WUSettings.NotificationLevel = 1 + $WUSettings.Save() + #> + + Write-Verbose "Search, download and install Windows Updates" + #Define update criteria. + $Criteria = "IsInstalled=0 and Type='Software'" + + Write-Verbose "Search for relevant updates" + Write-Progress -Activity "Windows Update" -Status "Searching for available and relevant updates" + $Searcher = New-Object -ComObject Microsoft.Update.Searcher + $SearchResult = $Searcher.Search($Criteria).Updates + + If ($SearchResult.Count -eq 0) { + Write-Verbose "No relevant updates found" + } + Else { + Write-Verbose "Download updates" + Write-Progress -Activity "Windows Update" -Status "Downloading updates" + $Session = New-Object -ComObject Microsoft.Update.Session + $Downloader = $Session.CreateUpdateDownloader() + $Downloader.Updates = $SearchResult + $Downloader.Download() + + Write-Verbose "Install updates" + Write-Progress -Activity "Windows Update" -Status "Installing updates" + $Installer = New-Object -ComObject Microsoft.Update.Installer + $Installer.Updates = $SearchResult + $Result = $Installer.Install() + } +} \ No newline at end of file diff --git a/Windows-PageFile.ps1 b/Windows-PageFile.ps1 new file mode 100644 index 0000000..21fa1f6 --- /dev/null +++ b/Windows-PageFile.ps1 @@ -0,0 +1,32 @@ +$AllVMs = Get-VM +$WinVMs = $AllVMs | where-object { $_.Name -like "*.nd.gov" -and $_.Name -notlike "des*" -and $_.Name -notlike "bnd*" -and $_.GuestId -like "Windows*" -and $_.GuestId -notlike "Windows7*" -and $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" } | sort-object Name + +$WinVMs | Set-Content C:\users\zmeier\desktop\WinVMs.txt + +$func = { + $CimInstanceCS = Get-WMIObject -Class Win32_ComputerSystem + $CimInstanceOS = Get-WMIObject -Class Win32_OperatingSystem + $CimInstancePFu = Get-WMIObject -Class Win32_PageFileUsage + $CimInstancePFs = Get-WMIObject -Class Win32_PageFileSetting + $CimInstanceVol = Get-WMIObject -Class Win32_Volume + + $obj = [PSCustomObject]@{ + ComputerName = $env:COMPUTERNAME + HardwareMemoryGB = [math]::round(($CimInstanceOS.TotalVisibleMemorySize / 1MB), 2); + PageFileAllocatedBaseSizeGB = [math]::round(($CimInstancePFu.AllocatedBaseSize / 1KB), 2); + CommittedMemoryGB = [math]::round(($CimInstanceOS.TotalVirtualMemorySize - $CimInstanceOS.FreeVirtualMemorySize) / 1MB, 2); + CurrentCommittedMemoryGB = [math]::round((Get-Counter -Counter '\memory\% committed bytes in use').CounterSamples.CookedValue / 1GB, 2) + PageFileSystemManaged = If ( $CimInstancePFs.InitialSize -eq 0) { "True" }Else { "False" } + PageFileInitialSizeGB = [math]::round($CimInstancePFs.InitialSize / 1KB, 2); + PageFileMaximumSizeGB = [math]::round($CimInstancePFs.MaximumSize / 1KB, 2); + PageFileCurrentUsageGB = [math]::round(($CimInstancePFu.CurrentUsage / 1KB), 2); + PageFilePeakUsageGB = [math]::round(($CimInstancePFu.PeakUsage / 1KB), 2); + PageFileLocation = $CimInstancePFu.Name; + PageDiskUsageGB = [math]::round((($CimInstanceVol | Where-Object { $_.DriveLetter -eq $CimInstancePFu.Name.split('\')[0] }).Capacity - ($CimInstanceVol | Where-Object { $_.DriveLetter -eq $CimInstancePFu.Name.split('\')[0] }).FreeSpace)/1GB, 2) + PageDiskSizeGB = [math]::round(($CimInstanceVol | Where-Object { $_.DriveLetter -eq $CimInstancePFu.Name.split('\')[0] }).Capacity / 1GB, 2); + PageDiskSizeCorrect = If ([math]::round(($CimInstanceVol | Where-Object { $_.DriveLetter -eq $CimInstancePFu.Name.split('\')[0] }).Capacity / 1GB, 2) -lt [math]::round(($CimInstanceOS.TotalVisibleMemorySize / 1MB), 2)) { $true } Else { $false }; + PageFileMaxCorrect = If ([math]::round($CimInstancePFs.MaximumSize / 1KB, 2) -ne 0 -and [math]::round($CimInstancePFs.MaximumSize / 1KB, 2) -lt ([math]::round(($CimInstanceVol | Where-Object { $_.DriveLetter -eq $CimInstancePFu.Name.split('\')[0] }).Capacity / 1GB, 2) - 0.5)) { $true }Else { $false }; + } + $obj +} +Invoke-Command -ComputerName $WinVMs -ScriptBlock $func -Credential $AdminCred -ov x \ No newline at end of file diff --git a/Windows-SecurityLogStuff.ps1 b/Windows-SecurityLogStuff.ps1 new file mode 100644 index 0000000..77204b0 --- /dev/null +++ b/Windows-SecurityLogStuff.ps1 @@ -0,0 +1,29 @@ +1 5:51.158 $x = Get-WinEvent -ComputerName localhost -LogName Security + 2 0.584 $x + 3 0.570 $x.Message | select -first 200 + 4 4.902 $x | where-object id -eq 4624 + 5 7.425 $y=$x | where-object id -eq 4624 + 6 1.066 $y.ToXml() + 7 0.072 $y.ToXml().Event.EventData.Data + 8 0.045 $y.ToXml().Event + 9 0.875 $y.ToXml() + 10 0.440 $xEvt=[xml]$y.ToXml() + 11 0.183 $y + 12 0.021 cls + 13 0.002 $y.count + 14 0.001 $x.count + 15 0.000 $event=$x + 16 0.000 $events=$x + 17 2.204 $events | ForEach-Object{… + 18 1.357 $events | ForEach-Object{… + 19 6.452 $events | ForEach-Object{… + 20 3:09.264 $events | ForEach-Object{… + 21 6:49.545 $z=$events | ForEach-Object{… + 22 0.372 $z + 23 0.027 $z | select -first 20 + 24 1:15.379 $z.'#text' + 25 10.290 $z | group-object '#.text' + 26 0.007 $z | select -first 20 + 27 8.744 $z | group-object '#text' + 28 13.311 $z | where-object '#text' -like "*jndi*" + 29 1.299 $x | select -last 1 \ No newline at end of file diff --git a/ZM.ModuleExample/0.0.1/Private/Get-ZMPrivate.ps1 b/ZM.ModuleExample/0.0.1/Private/Get-ZMPrivate.ps1 new file mode 100644 index 0000000..0bf26c2 --- /dev/null +++ b/ZM.ModuleExample/0.0.1/Private/Get-ZMPrivate.ps1 @@ -0,0 +1,18 @@ +function Get-ZMPrivate { + [CmdletBinding()] + param ( + + ) + + begin { + + } + + process { + Write-Warning -Message ("Hello Private!!1!") + } + + end { + + } +} diff --git a/ZM.ModuleExample/0.0.1/Public/Get-ZMPublic.ps1 b/ZM.ModuleExample/0.0.1/Public/Get-ZMPublic.ps1 new file mode 100644 index 0000000..8a580b3 --- /dev/null +++ b/ZM.ModuleExample/0.0.1/Public/Get-ZMPublic.ps1 @@ -0,0 +1,18 @@ +function Get-ZMPublic { + [CmdletBinding()] + param ( + + ) + + begin { + + } + + process { + Write-Warning -Message ("Hello Public!!1!") + } + + end { + + } +} \ No newline at end of file diff --git a/ZM.ModuleExample/0.0.1/Public/Get-ZMPublicAndPrivate.ps1 b/ZM.ModuleExample/0.0.1/Public/Get-ZMPublicAndPrivate.ps1 new file mode 100644 index 0000000..64b9b52 --- /dev/null +++ b/ZM.ModuleExample/0.0.1/Public/Get-ZMPublicAndPrivate.ps1 @@ -0,0 +1,19 @@ +function Get-ZMPublicAndPrivate { + [CmdletBinding()] + param ( + + ) + + begin { + + } + + process { + Get-ZMPrivate + Write-Warning -Message ("Hello Public!!1!") + } + + end { + + } +} \ No newline at end of file diff --git a/ZM.ModuleExample/0.0.1/ZM.ModuleExample.psd1 b/ZM.ModuleExample/0.0.1/ZM.ModuleExample.psd1 new file mode 100644 index 0000000..caab208 --- /dev/null +++ b/ZM.ModuleExample/0.0.1/ZM.ModuleExample.psd1 @@ -0,0 +1,132 @@ +# +# Module manifest for module 'ZM.ModuleExample' +# +# Generated by: zmeier +# +# Generated on: 5/2/2023 +# + +@{ + +# Script module or binary module file associated with this manifest. +RootModule = 'ZM.ModuleExample.psm1' + +# Version number of this module. +ModuleVersion = '0.0.1' + +# Supported PSEditions +# CompatiblePSEditions = @() + +# ID used to uniquely identify this module +GUID = '014b6590-d1a2-472d-88a9-a48d2d257ed5' + +# Author of this module +Author = 'zmeier' + +# Company or vendor of this module +CompanyName = 'Unknown' + +# Copyright statement for this module +Copyright = '(c) zmeier. All rights reserved.' + +# Description of the functionality provided by this module +# Description = '' + +# Minimum version of the PowerShell engine required by this module +# PowerShellVersion = '' + +# Name of the PowerShell host required by this module +# PowerShellHostName = '' + +# Minimum version of the PowerShell host required by this module +# PowerShellHostVersion = '' + +# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. +# DotNetFrameworkVersion = '' + +# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. +# ClrVersion = '' + +# Processor architecture (None, X86, Amd64) required by this module +# ProcessorArchitecture = '' + +# Modules that must be imported into the global environment prior to importing this module +# RequiredModules = @() + +# Assemblies that must be loaded prior to importing this module +# RequiredAssemblies = @() + +# Script files (.ps1) that are run in the caller's environment prior to importing this module. +# ScriptsToProcess = @() + +# Type files (.ps1xml) to be loaded when importing this module +# TypesToProcess = @() + +# Format files (.ps1xml) to be loaded when importing this module +# FormatsToProcess = @() + +# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess +# NestedModules = @() + +# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. +FunctionsToExport = '*' + +# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. +CmdletsToExport = '*' + +# Variables to export from this module +VariablesToExport = '*' + +# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. +AliasesToExport = '*' + +# DSC resources to export from this module +# DscResourcesToExport = @() + +# List of all modules packaged with this module +# ModuleList = @() + +# List of all files packaged with this module +# FileList = @() + +# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. +PrivateData = @{ + + PSData = @{ + + # Tags applied to this module. These help with module discovery in online galleries. + # Tags = @() + + # A URL to the license for this module. + # LicenseUri = '' + + # A URL to the main website for this project. + # ProjectUri = '' + + # A URL to an icon representing this module. + # IconUri = '' + + # ReleaseNotes of this module + # ReleaseNotes = '' + + # Prerelease string of this module + # Prerelease = '' + + # Flag to indicate whether the module requires explicit user acceptance for install/update/save + # RequireLicenseAcceptance = $false + + # External dependent modules of this module + # ExternalModuleDependencies = @() + + } # End of PSData hashtable + +} # End of PrivateData hashtable + +# HelpInfo URI of this module +# HelpInfoURI = '' + +# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. +# DefaultCommandPrefix = '' + +} + diff --git a/ZM.ModuleExample/0.0.1/ZM.ModuleExample.psm1 b/ZM.ModuleExample/0.0.1/ZM.ModuleExample.psm1 new file mode 100644 index 0000000..9abde6a --- /dev/null +++ b/ZM.ModuleExample/0.0.1/ZM.ModuleExample.psm1 @@ -0,0 +1,23 @@ +#Get public and private function definition files. +$Public = @( Get-ChildItem -Path $PSScriptRoot\Public\*.ps1 -ErrorAction SilentlyContinue ) +$Private = @( Get-ChildItem -Path $PSScriptRoot\Private\*.ps1 -ErrorAction SilentlyContinue ) + +#Dot source the files +Foreach($import in @($Public + $Private)) +{ + Try + { + . $import.fullname + } + Catch + { + Write-Error -Message "Failed to import function $($import.fullname): $_" + } +} + +# Here I might... +# Read in or create an initial config file and variable +# Export Public functions ($Public.BaseName) for WIP modules +# Set variables visible to the module and its functions only + +Export-ModuleMember -Function $Public.Basename \ No newline at end of file diff --git a/ZMBackupLocalADORepo.ps1 b/ZMBackupLocalADORepo.ps1 new file mode 100644 index 0000000..8c679d8 --- /dev/null +++ b/ZMBackupLocalADORepo.ps1 @@ -0,0 +1,28 @@ +Set-Location D:\ZM-ADOExport\Backup + +git config --global --add safe.directory D:\ZM-ADOExport\Backup +git add * +git commit -m "update" +git push + +Set-Location D:\ZM-ADOExport\PwshProfiles + +git config --global --add safe.directory D:/ZM-ADOExport/PwshProfiles +git add * +git commit -m "update" +git push + +Set-Location D:\ZM-ADOExport\Personal + +git config --global --add safe.directory D:/ZM-ADOExport/Personal +git add * +git commit -m "update" +git push + +Set-Location D:\ZM-ADOExport\Sandbox + +git config --global --add safe.directory D:/ZM-ADOExport/Sandbox +git add * +git commit -m "update" +git push + diff --git a/ZMBackupModules.ps1 b/ZMBackupModules.ps1 new file mode 100644 index 0000000..4eb6436 --- /dev/null +++ b/ZMBackupModules.ps1 @@ -0,0 +1,48 @@ +#start-transcript "D:\log.log" +xcopy C:\repos\NDGOV_CS\ C:\repos\ZM_Backup\_NDGOV_CS\ /s /e /Y +xcopy C:\repos\NDGOV_WindowsTeam\ C:\repos\ZM_Backup\_NDGOV_WindowsTeam\ /s /e /Y + +#Copy-Item -Path D:\ADO\NDGOV_ITD\ -exclude *.git -Destination D:\ADO\ZM_Sandbox\_NDGOV_ITD_backup -Recurse -Force +#Get-ChildItem -Path D:\ADO\ZM_Sandbox\_NDGOV_ITD_backup -Directory -Recurse -include *.git | remove-item -Force -recurse -Confirm:$false + +If (Test-Path -Path $profile.AllUsersAllHosts) { + Copy-Item -Path $profile.AllUsersAllHosts -Destination C:\repos\ZM_Backup\PwshProfiles\work\AllUsersAllHosts.ps1 -Force +} +If (Test-Path -Path $profile.AllusersCurrentHost) { + Copy-Item -Path $profile.AllusersCurrentHost -Destination C:\repos\ZM_Backup\PwshProfiles\work\AllusersCurrentHost.ps1 -Force +} +If (Test-Path -Path $profile.CurrentUserAllHosts) { + Copy-Item -Path $profile.CurrentUserAllHosts -Destination C:\repos\ZM_Backup\PwshProfiles\work\CurrentUserAllHosts.ps1 -Force +} +If (Test-Path -Path $profile.CurrentUserCurrentHost) { + Copy-Item -Path $profile.CurrentUserCurrentHost -Destination C:\repos\ZM_Backup\PwshProfiles\work\CurrentUserCurrentHost.ps1 -Force +} +If (Test-Path -Path "C:\Users\zmeier\AppData\Local\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json") { + Copy-Item -Path "C:\Users\zmeier\AppData\Local\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json" -Destination "C:\repos\ZM_Backup\PwshProfiles\work\WindowsTerminal_settings.json" +} +If (Test-Path -Path "C:\Users\zmeier\AppData\Roaming\Code\User\keybindings.json") { + Copy-Item -Path "C:\Users\zmeier\AppData\Roaming\Code\User\keybindings.json" -Destination "C:\repos\ZM_Backup\VSCodeSettings\work\keybindings.json" +} + + +Set-Location C:\repos\ZM_Backup\ + +git config --global --add safe.directory C:/repos/ZM_Backup +git add * +git commit -m "update" +git push + +<#Set-Location D:\GitHub\PwshProfiles\ + +git config --global --add safe.directory D:/GitHub/ADO_Backup +git add * +git commit -m "update" +git push +#> +Set-Location C:\repos\ZM_Sandbox\ + +git config --global --add safe.directory C:/repos/ZM_Sandbox +git add * +git commit -m "update" +git push + \ No newline at end of file diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 0000000..82e5f6d --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,29 @@ +# Starter pipeline +# Start with a minimal pipeline that you can customize to build and deploy your code. +# Add steps that build, run tests, deploy, and more: +# https://aka.ms/yaml + +trigger: +- master + +pool: + vmImage: ubuntu-latest + +steps: +- script: echo Hello, world! + displayName: 'Run a one-line script' + +- script: | + echo Add other tasks to build, test, and deploy your project. + echo See https://aka.ms/yaml + displayName: 'Run a multi-line script' +- task: VMwareTask@1 + inputs: + vCenterConnection: 'vmvc1' + action: 'Deploy Virtual Machines using Template' + template: 'WS2019_zm_20190223' + vmList: 'deploy100' + targetdc: 'Datacenter' + computeType: 'ESXi Host' + hostname: 'vm00.kwyjibo.info' + datastore: 'LSSD_850Evo_S2RANX0H415341R' \ No newline at end of file diff --git a/backup-gpos.ps1 b/backup-gpos.ps1 new file mode 100644 index 0000000..f23a520 --- /dev/null +++ b/backup-gpos.ps1 @@ -0,0 +1,27 @@ +# Ashley's script to pull all OUs and their linked GPOs, dump to csv +$Timestamp = (Get-Date).ToString("yyyyMMdd_HHmmss") +Get-GPLinkReport | export-csv "D:\GPOs\^LinkReport\GPOLinks-$Timestamp.csv" -Force + +# import-csv Ashley's report, filter only ITD +$LinkReports = Get-ChildItem "D:\GPOs\^LinkReport\" | Sort-Object LastWriteTime -Descending +$FirstNewest = $LinkReports | select -first 1 +$SecondNewest = $LinkReports | select -first 2 | select -last 1 + +# check dates and backup any new changes +$compare = Compare-Object $FirstNewest $SecondNewest + + + + + +$GPOs=Get-GPO -All +ForEach($GPO in $GPOs) +{ + $GPOName = $GPO.DisplayName + $Timestamp = $GPO.ModificationTime.ToString("yyyyMMdd_HHmmss") + $FolderPath = "D:\GPOs\$GPOName\$Timestamp\" + If(!(Test-Path $FolderPath)) + { + New-Item -Path $FolderPath -Force -ItemType Directory + } + $GPO | Backup-GPO -Path $FolderPath diff --git a/gPLinkReport.ps1 b/gPLinkReport.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..9345b50e118e0300a3bc266577f11d7214bbc07b GIT binary patch literal 32858 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 aJQm-hO+KFcAK*OX@O=Me`(o1V@BSYJ?q^W| literal 0 HcmV?d00001 diff --git a/iLOCertificatesAutoWithSectigo.ps1 b/iLOCertificatesAutoWithSectigo.ps1 new file mode 100644 index 0000000..5ceb070 --- /dev/null +++ b/iLOCertificatesAutoWithSectigo.ps1 @@ -0,0 +1,227 @@ +Import-Module HPEiLOCmdlets +$iLOCred = $PrvCred + +# Connect to OneView, Get list of servers +Connect-OVMgmt -Hostname itdmdnsyncompt1.nd.gov -Credential $PrvCred -AuthLoginDomain nd.gov -LoginAcknowledge +$AllOVServers = Get-OVServer + +$iLOToRenew = @() + +ForEach ($OVServer in $AllOVServers) { + Write-Warning -Message ($OVServer.ServerName) + $iLODnsName = $null + + $iLODnsName = $OVServer.ServerName.split('.')[0] + "lo.nd.gov" + + # is iLO cert about to expire? + $tcp = New-Object Net.Sockets.TcpClient($iLODnsName, 443) + $ssl = New-Object Net.Security.SslStream( + $tcp.GetStream(), + $false, + ({ $true }) # accept any cert + ) + + $ssl.AuthenticateAsClient($iLODnsName) + + $cert = New-Object Security.Cryptography.X509Certificates.X509Certificate2 $ssl.RemoteCertificate + + $ssl.Dispose() + $tcp.Dispose() + + If ( $cert.NotAfter.AddDays(-30) -le (Get-Date) ) { + Write-Warning -Message "Certificate for $iLODnsName expires on $($cert.NotAfter), add to renewal list." + $iLOToRenew += $iLODnsName + } + + If ( $cert.subject -notlike "*.nd.gov*") { + Write-Warning -Message "Certificate for $iLODnsName is not a ND.gov cert, add to renewal list." + $iLOToRenew += $iLODnsName + } +} + +$iloToRenew = $iLOToRenew | Select-Object -Unique + +Write-Verbose -Message "Loop through iLOs to generate CSRs and request certs" + +$iLOConnections = ForEach ($iLOFqdn in $iLOToRenew) { + Connect-HPEiLO -Address $iLOFqdn -Credential $iLOCred -DisableCertificateAuthentication +} + +# Get-HPEiLOSSLCertificateInfo -Connection $iLOConnections -ov x +Write-Verbose -Message ([string]$iLOConnections.count + " iLO Connections established.") -Verbose + +ForEach ($iLOConnection in $iLOConnections) { + Start-HPEiLOCertificateSigningRequest -Connection $iLOConnection ` + -CommonName $iloConnection.Hostname ` + -Organization "State of North Dakota" ` + -Country US ` + -City Bismarck ` + -State "North Dakota" ` + -OrganizationalUnit NDIT +} + +Start-Sleep -Seconds 30 ## for some reason iLO needs time to generate a CSR + +# set static values while we wait +$RequesterEmail = 'vmware@nd.gov' +$ServerType = "Linux" +$Format = "x509CO" +$OrgId = 8133 + +$OrderIds = @() + +ForEach ($iloConnection in $iLOConnections) { + Write-Verbose -Message "Getting CSR for $($iLOConnection.Hostname)" + $CsrData = $null + + While ($CsrData.CertificateSigningRequest -eq $null) { + try { + $CsrData = Get-HPEiLOCertificateSigningRequest -Connection $iLOConnection + } + catch { + Write-Warning -Message "CSR not ready yet for $($iLOConnection.Hostname), waiting 10 seconds." + Start-Sleep -Seconds 10 + } + } + + + $AuthBody = @{ + grant_type = 'client_credentials' + client_id = $SectigoAPIKey.UserName + client_secret = $SectigoAPIKey.GetNetworkCredential().Password + } + + $AuthBaseAPIUrl = 'https://auth.sso.sectigo.com' + $BaseAPIUrl = 'https://admin.hard.sectigo.com' + + $tokenEndpoint = $AuthBaseAPIUrl + '/auth/realms/apiclients/protocol/openid-connect/token' + $tokenResponse = Invoke-RestMethod -Method Post -Uri $tokenEndpoint -ContentType 'application/x-www-form-urlencoded' -Body $AuthBody + $env:SectigoToken = $tokenResponse.access_token + + $headers = @{ + "Authorization" = "Bearer $env:SectigoToken" + "Content-Type" = "application/json" + } + + If ($env:SectigoToken) { Write-Warning -Message ("Sectigo Token Set " + $env:SectigoToken) } + + [string]$RequestUrl = $BaseAPIUrl + "/api/ssl/v1/enroll" + + $CertType = 2375 + $ServerTypeCode = 'Linux' + + $EnrollBody = @{ + orgId = $OrgId; + certType = $CertType + term = 365; + comments = "iLO Certificate Renewal for $($iloConnection.Hostname)" + serverType = $ServerTypeCode + csr = $CsrData.CertificateSigningRequest + externalRequester = "vmware@nd.gov" + customFields = @( + @{ + name = 'ApplicationName' + value = 'Infra-VMware' + } + ) + } + + $InvokeRestMethodParams = @{ + Uri = $RequestUrl + Method = 'Post' + Headers = $headers + Body = ($EnrollBody | ConvertTo-Json -Depth 10) + ContentType = 'application/json' + } + + $Response = Invoke-RestMethod @InvokeRestMethodParams #actual enrollment/request + $OrderIds += $Response.sslId +} + + +<## approval step -- can't approve own requests, need alternate method... auto-approval of some kind? +$ApproveUrl = $BaseAPIUrl + "/api/ssl/v1/approve/${OrderId}" +$ApproveBody = @{ + message = 'Approved VMware Auto' +} +$ApproveSplat = @{ + Uri = $ApproveUrl + Method = 'Post' + Headers = $headers + Body = ($ApproveBody) | ConvertTo-Json + ContentType = 'application/json' +} + +Invoke-RestMethod @ApproveSplat +#> + + + +## download the certificate - the first link email / "Certificate only, PEM encoded" + +### re-establish token with Sectigo +$tokenResponse = Invoke-RestMethod -Method Post -Uri $tokenEndpoint -ContentType 'application/x-www-form-urlencoded' -Body $AuthBody +$env:SectigoToken = $tokenResponse.access_token + +$headers = @{ + "Authorization" = "Bearer $env:SectigoToken" + "Content-Type" = "application/json" +} + +$Format = 'x509CO' + +ForEach ($OrderId in $OrderIds) { + $Certificate = $null + While ($Certificate.status -ne "Issued") { + $ValidateUrl = "${BaseAPIUrl}/api/ssl/v1/${OrderId}" + $ValidateSplat = @{ + Uri = $ValidateUrl + Method = 'Get' + Headers = $headers + } + + $Certificate = Invoke-RestMethod @ValidateSplat + } + + $CollectUrl = $BaseAPIUrl + "/api/ssl/v1/collect/${OrderId}?format=${Format}" + + $CommonName = $Certificate.commonName + + $DownloadSplat = @{ + Uri = $CollectUrl + Method = 'Get' + Headers = $headers + UseBasicParsing = $true + } + + Invoke-WebRequest @DownloadSplat -OutFile "C:\certs\$CommonName-$OrderId.pem" +} + +## set new certs on iLOs +$Certs = Get-ChildItem -Path "C:\certs\" -Filter "*.pem" +ForEach ($iLOConnection in $iLOConnections) { + Write-Verbose -Message "Uploading certificate to $($iLOConnection.Hostname)" -Verbose + $CertFileToUse = $Certs | Where-Object { $_.Name -like "$($iLOConnection.Hostname)*" } + $Cert = Get-Content -Path $CertFileToUse.FullName + + Import-HPEiLOCertificate -Certificate ($Cert | Out-String) -Connection $iLOConnection -Force +} + +ForEach ($iLODnsName in $iLOToRenew) { + # is iLO cert about to expire? + $tcp = New-Object Net.Sockets.TcpClient($iLODnsName, 443) + $ssl = New-Object Net.Security.SslStream( + $tcp.GetStream(), + $false, + ({ $true }) # accept any cert + ) + + $ssl.AuthenticateAsClient($iLODnsName) + + $newcert = New-Object Security.Cryptography.X509Certificates.X509Certificate2 $ssl.RemoteCertificate + + $ssl.Dispose() + $tcp.Dispose() + + $NewCert | select @{n='zSubject'; e={$NewCert.Subject.split(',')[0]}}, NotBefore, NotAfter +} \ No newline at end of file diff --git a/pers cleanup.ps1 b/pers cleanup.ps1 new file mode 100644 index 0000000..b76181f --- /dev/null +++ b/pers cleanup.ps1 @@ -0,0 +1,4 @@ +# Cleanup of Office / Aria logs +$Path = 'C:\users\!perslinkadmin\appdata\local\temp\' +Get-ChildItem -Path $Path -Name aria-*.log + diff --git a/readme.md b/readme.md index 4f67a83..6e4f5ca 100644 --- a/readme.md +++ b/readme.md @@ -1 +1 @@ -test 1 \ No newline at end of file +# Sandbox \ No newline at end of file