Joining two scripts - regex

First I made new script that make regex :
$input_path = 'C:\site-download\input.txt'
$output_file = 'C:\site-download\output.txt'
$regex = '(?<month>VPIP<\/span><span class=""right"">\d{2}.\d{1})'
$regex2 = '(?<month>Winrate<\/span><span class=""right"">\d{1}.\d{1})'
$regex3 = '(?<month>PFR<\/span><span class=""right"">\d{2}.\d{1})'
$regex4 = '(?<month>Winnings<\/span><span class=""right"">\-[0-9]{1,9})'
$regex5 = '(?<month>3Bet<\/span><span class=""right"">\d{1}.\d{1})'
Select-String -Path $input_path -Pattern $regex -List | % { $_.Matches} | % { $_.Value } | Foreach-Object {$_ -replace '</span><span class=""right"">', ' = '} | Add-Content $output_file
Select-String -Path $input_path -Pattern $regex2 -List | % { $_.Matches} | % { $_.Value } |Foreach-Object {$_ -replace '</span><span class=""right"">', ' = '} | Add-Content $output_file
Select-String -Path $input_path -Pattern $regex3 -List | % { $_.Matches} | % { $_.Value } | Foreach-Object {$_ -replace '</span><span class=""right"">', ' = '} | Add-Content $output_file
Select-String -Path $input_path -Pattern $regex4 -List | % { $_.Matches} | % { $_.Value } |Foreach-Object {$_ -replace '</span><span class=""right"">', ' = '} | Add-Content $output_file
Select-String -Path $input_path -Pattern $regex5 -List | % { $_.Matches} | % { $_.Value } | Foreach-Object {$_ -replace '</span><span class=""right"">', ' = '} | Add-Content $output_file
Its working good so far.
Second script I found in web (also working good):
Function Register-Watcher {
param ($folder)
$filter = "*.*" #all files
$watcher = New-Object IO.FileSystemWatcher $folder, $filter -Property #{
IncludeSubdirectories = $false
EnableRaisingEvents = $true
}
$changeAction = [scriptblock]::Create('
# This is the code which will be executed every time a file change is detected
$path = $Event.SourceEventArgs.FullPath
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
Write-Host "The file $name was $changeType at $timeStamp"
')
Register-ObjectEvent $Watcher "Changed" -Action $changeAction
}
Register-Watcher "C:\site-download"
So basically I'm working to find out how I can add first script to second.
I tried something this:
Function Register-Watcher {
param ($folder)
$filter = "*.*" #all files
$watcher = New-Object IO.FileSystemWatcher $folder, $filter -Property #{
IncludeSubdirectories = $false
EnableRaisingEvents = $true
}
$changeAction = [scriptblock]::Create('
# This is the code which will be executed every time a file change is detected
$path = $Event.SourceEventArgs.FullPath
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
Write-Host "The file $name was $changeType at $timeStamp"
$input_path = $name
$output_file = 'C:\site-download\output.txt'
$regex = '(?<month>VPIP<\/span><span class=""right"">\d{2}.\d{1})'
$regex2 = '(?<month>Winrate<\/span><span class=""right"">\d{1}.\d{1})'
$regex3 = '(?<month>PFR<\/span><span class=""right"">\d{2}.\d{1})'
$regex4 = '(?<month>Winnings<\/span><span class=""right"">\-[0-9]{1,9})'
$regex5 = '(?<month>3Bet<\/span><span class=""right"">\d{1}.\d{1})'
Select-String -Path $input_path -Pattern $regex -List | % { $_.Matches} | % { $_.Value } | Foreach-Object {$_ -replace '</span><span class=""right"">', ' = '} | Add-Content $output_file
Select-String -Path $input_path -Pattern $regex2 -List | % { $_.Matches} | % { $_.Value } |Foreach-Object {$_ -replace '</span><span class=""right"">', ' = '} | Add-Content $output_file
Select-String -Path $input_path -Pattern $regex3 -List | % { $_.Matches} | % { $_.Value } | Foreach-Object {$_ -replace '</span><span class=""right"">', ' = '} | Add-Content $output_file
Select-String -Path $input_path -Pattern $regex4 -List | % { $_.Matches} | % { $_.Value } |Foreach-Object {$_ -replace '</span><span class=""right"">', ' = '} | Add-Content $output_file
Select-String -Path $input_path -Pattern $regex5 -List | % { $_.Matches} | % { $_.Value } | Foreach-Object {$_ -replace '</span><span class=""right"">', ' = '} | Add-Content $output_file
')
Register-ObjectEvent $Watcher "Changed" -Action $changeAction
}
Register-Watcher "C:\site-download"
But keep getting some errors:
Select-String : Cannot bind argument to parameter 'Path' because it is null.
At line:1 char:21
+ select-string -Path $input_path -Pattern $regex -List | % { $_.Matches} | % { $_ ...
+ ~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Select-String], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.Sel‌​ectStringCommand
Can someone help me out to fix this last script?

Your regex script has single quotes (') in it which are breaking your scriptblock. Replace them with double quotes (").

What i have tested now:
Function Register-Watcher {
param ($folder)
$filter = "*.*" #all files
$watcher = New-Object IO.FileSystemWatcher $folder, $filter -Property #{
IncludeSubdirectories = $false
EnableRaisingEvents = $true
}
$changeAction = [scriptblock]::Create('
# This is the code which will be executed every time a file change is detected
$path = $Event.SourceEventArgs.FullPath
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
Write-Host "The file $name was $changeType at $timeStamp"
')
Register-ObjectEvent $Watcher "Created" -Action $changeAction
}
Register-Watcher "C:\site-download"
Function regex-inout { $input_path = 'C:\site-download\input.txt'
$output_file = "C:\site-download\output.txt"
$regex = "(?<month>VPIP<\/span><span class=""right"">\d{2}.\d{1})"
$regex2 = "(?<month>Winrate<\/span><span class=""right"">\d{1}.\d{1})"
$regex3 = "(?<month>PFR<\/span><span class=""right"">\d{2}.\d{1})"
$regex4 = "(?<month>Winnings<\/span><span class=""right"">\-[0-9]{1,9})"
$regex5 = "(?<month>3Bet<\/span><span class=""right"">\d{1}.\d{1})"
select-string -Path $input_path -Pattern $regex -List | % { $_.Matches} | % { $_.Value } | Foreach-Object {$_ -replace '</span><span class=""right"">', ' = '} | Add-Content $output_file
select-string -Path $input_path -Pattern $regex2 -List | % { $_.Matches} | % { $_.Value } |Foreach-Object {$_ -replace '</span><span class=""right"">', ' = '} | Add-Content $output_file
select-string -Path $input_path -Pattern $regex3 -List | % { $_.Matches} | % { $_.Value } | Foreach-Object {$_ -replace '</span><span class=""right"">', ' = '} | Add-Content $output_file
select-string -Path $input_path -Pattern $regex4 -List | % { $_.Matches} | % { $_.Value } |Foreach-Object {$_ -replace '</span><span class=""right"">', ' = '} | Add-Content $output_file
select-string -Path $input_path -Pattern $regex5 -List | % { $_.Matches} | % { $_.Value } | Foreach-Object {$_ -replace '</span><span class=""right"">', ' = '} | Add-Content $output_file
} regex-inout
Folder watch working good. But where should i move Function regex-inout so that when new files come to folder then this regex start work. At moment only folder watch working and regex didn't do nothing.
Sorry for my bad English.

Related

Add DOMAIN\Domain Admins group as Full Access to the orphaned Home Directory?

The below script was created by the great https://stackoverflow.com/users/9898643/theo to list all orphaned HomeDirectory:
$ServerHomeDirShare = "\\FileServer\HomeDir$"
$filter = "(Enabled -eq 'true')"
# get all user accounts from AD; only SamAccountName required
$users = Get-ADUser -Filter $filter | Select-Object -ExpandProperty SamAccountName
Get-ChildItem -Path $ServerHomeDirShare -Directory |
Where-Object { $users -notcontains ($_.Name -replace '^(\w+\.\w+).*', '$1') } |
Select-Object -Property Name, FullName,
#{ n = 'LastAccessTime'; e = { $_.LastAccessTime.ToString('yyyy-MM-dd HH:mm:ss') } },
#{ n = "Directory Size (MB)"; e = {
Try {
$Size = (Get-ChildItem -Path $_.FullName -Recurse -ErrorAction Stop |
Measure-Object Length -Sum).Sum / 1MB
[math]::Round($Size, 2)
}
Catch {
"ERROR: $($_.Exception.Message)"
}
}
} |
Export-Csv -NoTypeInformation -Path C:\UserProfilesNotExist-Size.csv
However, there is one more issue that needed fixing, to add DOMAIN\Domain Admins AD group as Full Access to the directory ACL, BUT ONLY when the directory is not accessible or throwing error.
$FullAccessADGroup = "DOMAIN\Domain Admins"
function Take-Ownership
{
param (
[String]$Folder
)
takeown.exe /A /F $Folder
$CurrentACL = Get-Acl $Folder
write-host "`n`t...Adding NT Authority\SYSTEM to $Folder" -ForegroundColor Yellow
$SystemACLPermission = "NT AUTHORITY\SYSTEM", "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow"
$SystemAccessRule = new-object System.Security.AccessControl.FileSystemAccessRule $SystemACLPermission
$CurrentACL.AddAccessRule($SystemAccessRule)
write-host "`t...Adding Infrastructure Services to $Folder" -ForegroundColor Yellow
$AdminACLPermission = $FullAccessADGroup, "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow"
$SystemAccessRule = new-object System.Security.AccessControl.FileSystemAccessRule $AdminACLPermission
$CurrentACL.AddAccessRule($SystemAccessRule)
Set-Acl -Path $Folder -AclObject $CurrentACL
}
function Test-Folder($FolderToTest) {
$error.Clear()
$ErrorArray = #()
Get-ChildItem $FolderToTest -Recurse -ErrorAction SilentlyContinue | Select-Object FullName
if ($error) {
$ErrorArray = $error + $ErrorArray
foreach ($err in $ErrorArray) {
if ($err.FullyQualifiedErrorId -eq "DirUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand") {
Write-Host Unable to access $err.TargetObject -ForegroundColor Red
Write-Host Attempting to take ownership of $err.TargetObject -ForegroundColor Yellow
Take-Ownership($err.TargetObject)
Test-Folder($err.TargetObject)
}
}
}
}
Test-Folder $source
Because even though I am using DOMAIN\Administrator account to execute the script above, I cannot get the directory size or even opened the directory via the UNCPath, this is the error:
ERROR: Access to the path '\\FileServer\HomeDir$\Jane.Liz.V2' is denied.
ERROR: Access to the path '\\FileServer\HomeDir$\Lisa.Chan.V5' is denied.
ERROR: Access to the path '\\FileServer\HomeDir$\Carolline.Marce.V6' is denied.
...

Remove part of Powershell Result within Invoke Command

I have the following line:
"OSType" = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-CimInstance SoftwareLicensingProduct | Where-Object -FilterScript { ($_.Description -like "W*" -and $_.licensestatus -eq 1 ) } | select-object -first 1 -ExpandProperty Description} `
That produces: OSType : Windows Operating System - Windows(R) 7, OEM_SLP channel
I am doing this in a ForEach statement and it works fine but I want the output to be just: OSType: OEM_SLP
I can do this to break it apart but then it takes the value from the last computer and puts it in for every entry:
$OSType = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-CimInstance SoftwareLicensingProduct | Where-Object -FilterScript { ($_.Description -like "W*" -and $_.licensestatus -eq 1 ) } | select-object -first 1 -ExpandProperty Description} `
$OS1 = $OSType.Split(',')[1]
$OS2 = $OS1.Split(' ')[1]
"OSType" = $OS2
It fails if I try to use the Invoke command on the bottom 3 lines. Any Ideas?
Here is my entire script:
$computers = Get-Content -Path "C:\Computers.txt"
$Results = #()
ForEach ($Computer in $Computers) {
$Results += New-Object PSObject -Property #{
"Computer" = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-WmiObject –class Win32_processor | select-object -first 1 -ExpandProperty SystemName } `
"CPU1" = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-WmiObject –class Win32_processor | Where-Object -FilterScript { ($_.SocketDesignation -like "*1*") -or ($_.SocketDesignation -like "*0*") } | select-object -first 1 -ExpandProperty Name } `
"Cores1" = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-WmiObject –class Win32_processor | Where-Object -FilterScript { ($_.SocketDesignation -like "*1*") -or ($_.SocketDesignation -like "*0*") } | select-object -first 1 -ExpandProperty NumberOfCores } `
"LogProc1" = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-WmiObject –class Win32_processor | Where-Object -FilterScript { ($_.SocketDesignation -like "*1*") -or ($_.SocketDesignation -like "*0*") } | select-object -first 1 -ExpandProperty NumberOfLogicalProcessors }
"CPU2" = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-WmiObject –class Win32_processor | Where-Object -FilterScript { ($_.SocketDesignation -like "*2*") -or ($_.SocketDesignation -like "*#1*") } | select-object -first 1 -ExpandProperty Name } `
"Cores2" = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-WmiObject –class Win32_processor | Where-Object -FilterScript { ($_.SocketDesignation -like "*2*") -or ($_.SocketDesignation -like "*#1*") } | select-object -first 1 -ExpandProperty NumberOfCores } `
"LogProc2" = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-WmiObject –class Win32_processor | Where-Object -FilterScript { ($_.SocketDesignation -like "*2*") -or ($_.SocketDesignation -like "*#1*") } | select-object -first 1 -ExpandProperty NumberOfLogicalProcessors } `
"OS" = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-CimInstance Win32_OperatingSystem | Select-Object -ExpandProperty Caption } `
#"OSType" = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-CimInstance SoftwareLicensingProduct | Where-Object -FilterScript { ($_.Description -like "W*" -and $_.licensestatus -eq 1 ) } | select-object -first 1 -ExpandProperty Description} `
$OSType = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-CimInstance SoftwareLicensingProduct | Where-Object -FilterScript { ($_.Description -like "W*" -and $_.licensestatus -eq 1 ) } | select-object -first 1 -ExpandProperty Description} `
$OS1 = $OSType.Split(',')[1]
$OS2 = $OS1.Split(' ')[1]
"OSType" = $OS2
"SP" = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-CimInstance Win32_OperatingSystem | Select-Object -ExpandProperty ServicePackMajorVersion } `
"OSArch" = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-CimInstance Win32_OperatingSystem | Select-Object -ExpandProperty OSArchitecture } `
"Office" = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Where-Object -FilterScript { (($_.Publisher -like "Microsoft*") -and ($_.DisplayName -like "*Office 64*")) } | Select-Object -first 1 -ExpandProperty DisplayName }
"FullSQL" = Invoke-Command -ComputerName $Computer -ScriptBlock {If (Test-Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names") { Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Where-Object -FilterScript { (($_.Publisher -like "Microsoft*") -and ($_.DisplayName -like "Microsoft SQL Server*(*-bit)")) } | Select-Object -first 1 -ExpandProperty DisplayName }}
}
}
$Results | Select-Object Computer, CPU1, Cores1, LogProc1, CPU2, Cores2, LogProc2, OS, OSType, SP, OSArch, Office, FullSQL | Sort-Object Computer
This should work:
$OSType = (Invoke-Command -ComputerName $Computer -ScriptBlock {
Get-CimInstance SoftwareLicensingProduct |
Where-Object -FilterScript { ($_.Description -like "W*" -and $_.licensestatus -eq 1 ) } |
select-object -first 1 -ExpandProperty Description
}) -replace '.*,\s?(\S+).*', '$1'
However, I would highly recommend you to invoke Get-WmiObject –class Win32_processor only once before you creating the object. Just store the result in a variable and access / filter it.
Edit:
To get rid of all your Get-WmiObject calls, you could do something like this:
ForEach ($Computer in $Computers) {
$win32processor = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-WmiObject –class Win32_processor }
$Results += New-Object PSObject -Property #{
"Computer" = $win32processor | select-object -first 1 -ExpandProperty SystemName
"CPU1" = $win32processor | Where-Object -FilterScript { ($_.SocketDesignation -like "*1*") -or ($_.SocketDesignation -like "*0*") } | select-object -first 1 -ExpandProperty Name
#........

how can we unpublish item with its subitem for one particular language in sitecore?

we have option in ribbon publish - > change but that is not unpublishing subitems .
how can we unpublish item with its subitem for one particular language in sitecore ?
Thanks
Approach 1:
In the Publish ribbon, click the Change button and UNCHECK Publishable on the Item tab. Now delete the parent item with sub-items and the item will be removed from the published DB. Next go back to the item and CHECK Publishable, then publish the item only in the language you want.
Approach 2:
Use the database selector in the Sitecore shell (bottom right corner) and select your publishing target DB (e.g. "web"). GO into that tree, find the item in the language and delete that version. After that you'll need to go to your public site's cache page and clear that cache manually: http://host/sitecore/admin/cache.aspx
Approach 3:
Delete the item in the master DB, publish the parent, restore it form the recycle bin, publish it again live but not in the language you don't want.
some script is also fine :)
just publish site after use it
function GetItemDatasources {
[CmdletBinding()]
param([Item]$Item)
# grab all datasources that are not header and footer elements
return Get-Rendering -Item $item -FinalLayout -Device (Get-LayoutDevice -Default) |
Where-Object { -not [string]::IsNullOrEmpty($_.Datasource)} |
Where-Object { $_.Placeholder -ne 'Above Page Content' } |
Where-Object { $_.Placeholder -ne 'Below Page Content' } |
ForEach-Object { Get-Item "$($item.Database):" -ID $_.Datasource }
# ForEach-Object { Write-Host ($_ | Format-List | Out-String) }
}
$location = get-location
$languages = Get-ChildItem "master:\sitecore\system\Languages"
$currentLanguage = [Sitecore.Context]::Language.Name
$langOptions = #{};
foreach ($lang in $languages) {
$langOptions[$lang.Name] = $lang.Name
}
$result = Read-Variable -Parameters `
#{ Name = "destinationLanguages"; Title="Language(s) for clean up "; Options=$langOptions; Editor="checklist"; },
#{ Name = "includeSubitems"; Value=$false; Title="Include Subitems"; Columns = 4;} `
-Description "Select an languages that should be cleanup" `
-Title "Cleanup Language" -Width 650 -Height 660 -OkButtonName "Proceed" -CancelButtonName "Cancel" -ShowHints
if($result -ne "ok") {
Exit
}
Write-Host "destinationLanguages = $destinationLanguages"
$items = #()
$items += Get-Item $location
# add optional subitems
if ($includeSubitems) {
$items += Get-ChildItem $location -Recurse
}
# Remove any duplicates, based on ID
$items = $items | Sort-Object -Property 'ID' -Unique
$items | ForEach-Object { Write-Host ($_.ItemPath | Sort-Object | Format-List | Out-String) }
$message = "You are about to cleanup <span style='font-weight: bold'>$($items.Count) item(s)</span> with the following options:<br>"
$message += "<br><table>"
$message += "<tr><td style='width: auto'>Languages:</td><td>$destinationLanguages</td></tr>"
$message += "<tr><td style='width: auto'>Include Subitems:</td><td>$includeSubitems</td></tr>"
$message += "</table>"
$message += "<br><p style='font-weight: bold'>Are you sure?</p>"
$proceed = Show-Confirm -Title $message
if ($proceed -ne 'yes') {
Write-Host "Canceling"
Exit
}
Write-Host "Proceeding with execution"
$items | ForEach-Object { Remove-ItemVersion -Item $_ -Language $destinationLanguages -ExcludeLanguage "en*" }
I did this
function GetItemDatasources {
[CmdletBinding()]
param([Item]$Item)
# grab all datasources that are not header and footer elements
return Get-Rendering -Item $item -FinalLayout -Device (Get-LayoutDevice -Default) |
Where-Object { -not [string]::IsNullOrEmpty($_.Datasource)} |
Where-Object { $_.Placeholder -ne 'Above Page Content' } |
Where-Object { $_.Placeholder -ne 'Below Page Content' } |
ForEach-Object { Get-Item "$($item.Database):" -ID $_.Datasource }
# ForEach-Object { Write-Host ($_ | Format-List | Out-String) }
}
$location = get-location
$languages = Get-ChildItem "master:\sitecore\system\Languages"
$currentLanguage = [Sitecore.Context]::Language.Name
$langOptions = #{};
$actions = #{};
$actions["Unpublish"] = "1";
$actions["Publish"] = "";
foreach ($lang in $languages) {
$langOptions[$lang.Name] = $lang.Name
}
$result = Read-Variable -Parameters `
#{ Name = "destinationLanguages"; Title="Language(s) for publich/unpublish"; Options=$langOptions; Editor="checklist"; },
#{ Name = "includeSubitems"; Value=$false; Title="Include Subitems"; Columns = 4;},
#{ Name = "action"; Value="1"; Title="Action"; Options=$actions; Tooltip="Unpublish: Set language as unblishded on all langauge vestions.<br>Publish: Set language as publishded on all langauge vestions."; }`
-Description "Select languages that should be proceed during updates" `
-Title "Language Publish - Unpublish" -Width 650 -Height 660 -OkButtonName "Proceed" -CancelButtonName "Cancel" -ShowHints
if($result -ne "ok") {
Exit
}
Write-Host "destinationLanguages = $destinationLanguages"
$items = #()
$items += Get-Item $location
# add optional subitems
if ($includeSubitems) {
$items += Get-ChildItem $location -Recurse
}
# Remove any duplicates, based on ID
$items = $items | Sort-Object -Property 'ID' -Unique
$items | ForEach-Object { Write-Host ($_.ItemPath | Sort-Object | Format-List | Out-String) }
$message = "You are about to publish/unpublish <span style='font-weight: bold'>$($items.Count) item(s)</span> with the following options:<br>"
$message += "<br><table>"
$message += "<tr><td style='width: auto'>Languages:</td><td>$destinationLanguages</td></tr>"
$message += "<tr><td style='width: auto'>Include Subitems:</td><td>$includeSubitems</td></tr>"
$message += "</table>"
$message += "<br><p style='font-weight: bold'>Are you sure?</p>"
$proceed = Show-Confirm -Title $message
if ($proceed -ne 'yes') {
Write-Host "Canceling"
Exit
}
Write-Host "Proceeding with execution"
$items | ForEach-Object {
$vitems = Get-Item $_.ID -Language $destinationLanguages -Version *
$vitems | ForEach-Object {
$_.Editing.BeginEdit()
$_["__Hide version"] = $action
$_.Editing.EndEdit()
}
}

Powershell function to replace or add lines in text files

I'm working on a powershell script that modifies config files. I have files like this:
#####################################################
# comment about logentrytimeout
#####################################################
Logentrytimeout= 1800
who should look like this:
#####################################################
# comment about logentrytimeout
#####################################################
Logentrytimeout= 180
disablepostprocessing = 1
segmentstarttimeout = 180
If there is a key set(Logentrytimeout), just update it to the given value. Ignore comments, where the key is mentioned(lines that start with #). The Key is case insensitive.
If the key is not set(disablepostprocessing and segmentstarttimeout), append key and value to the file. My function so far goes like this:
function setConfig( $file, $key, $value )
{
(Get-Content $file) |
Foreach-Object {$_ -replace "^"+$key+".=.+$", $key + " = " + $value } |
Set-Content $file
}
setConfig divider.conf "Logentrytimeout" "180"
setConfig divider.conf "disablepostprocessing" "1"
setConfig divider.conf "segmentstarttimeout" "180"
What is the correct regex?
How do I check if there was a replacement?
If there was no replacement: How can I append $key+" = "+$value to the file then?
Assuming the $key you want to replace is always at the beginning of a line, and that it contains no special regex characters
function setConfig( $file, $key, $value ) {
$content = Get-Content $file
if ( $content -match "^$key\s*=" ) {
$content -replace "^$key\s*=.*", "$key = $value" |
Set-Content $file
} else {
Add-Content $file "$key = $value"
}
}
setConfig "divider.conf" "Logentrytimeout" "180"
If there is no replacement $key = $value will be appended to the file.
Updated version of the functions above with some parametrisation and verbose output if required.
Function Set-FileConfigurationValue()
{
[CmdletBinding(PositionalBinding=$false)]
param(
[Parameter(Mandatory)][string][ValidateScript({Test-Path $_})] $Path,
[Parameter(Mandatory)][string][ValidateNotNullOrEmpty()] $Key,
[Parameter(Mandatory)][string][ValidateNotNullOrEmpty()] $Value,
[Switch] $ReplaceExistingValue,
[Switch] $ReplaceOnly
)
$content = Get-Content -Path $Path
$regreplace = $("(?<=$Key).*?=.*")
$regValue = $("=" + $Value)
if (([regex]::Match((Get-Content $Path),$regreplace)).success)
{
If ($ReplaceExistingValue)
{
Write-Verbose "Replacing configuration Key ""$Key"" in configuration file ""$Path"" with Value ""$Value"""
(Get-Content -Path $Path) | Foreach-Object { [regex]::Replace($_,$regreplace,$regvalue) } | Set-Content $Path
}
else
{
Write-Warning "Key ""$Key"" found in configuration file ""$Path"". To replace this Value specify parameter ""ReplaceExistingValue"""
}
}
elseif (-not $ReplaceOnly)
{
Write-Verbose "Adding configuration Key ""$Key"" to configuration file ""$Path"" using Value ""$Value"""
Add-Content -Path $Path -Value $("`n" + $Key + "=" + $Value)
}
else
{
Write-Warning "Key ""$Key"" not found in configuration file ""$Path"" and parameter ""ReplaceOnly"" has been specified therefore no work done"
}
}
I'd do this:
function setConfig( $file, $key, $value )
{
$regex = '^' + [regex]::escape($key) + '\s*=.+'
$replace = "$key = $value"
$old = get-content $file
$new = $old -replace $regex,$replace
if (compare-object $old $new)
{
Write-Host (compare-object $old $new | ft -auto | out-string) -ForegroundColor Yellow
$new | set-content $file
}
else {
$replace | add-content $file
Write-Host "$replace added to $file" -ForegroundColor Cyan
}
}
Edit: added a replacement bell, and a not match whistle.
Change the function to this:
function Set-Config( $file, $key, $value )
{
$regreplace = $("(?<=$key).*?=.*")
$regvalue = $(" = " + $value)
if (([regex]::Match((Get-Content $file),$regreplace)).success) {
(Get-Content $file) `
|Foreach-Object { [regex]::Replace($_,$regreplace,$regvalue)
} | Set-Content $file
} else {
Add-Content -Path $file -Value $("`n" + $key + " = " + $value)
}
}
Then when you call the function, use this format:
Set-Config -file "divider.conf" -key "Logentrytimeout" -value "180"
Edit: I forgot your requirement of adding the line if it doesn't exist. This will check for the $key, if it exists it will set its value to $value. If it doesn't exist it will add $key = $value to the end of the file. I also renamed the function to be more consistent with power shell naming conventions.
#CarlR Function it's for PowerShell Version 3. This it's the same adapted to PowerShell Version 2.
EDIT: Changed regular expression to fix two bugs on Set-FileConfigurationValue:
If you have one line like this:
; This is a Black line
And you try to do:
Set-FileConfigurationValue $configFile "Black" 20 -ReplaceExistingValue
You get one message about "Replacing" but nothing happens.
If you have two lines like these:
filesTmp=50
Tmp=50
And you try to do:
Set-FileConfigurationValue $configFile "Tmp" 20 -ReplaceExistingValue
You get the two lines changed!
filesTmp=20
Tmp=20
This is the final version:
Function Set-FileConfigurationValue()
{
[CmdletBinding()]
param(
[Parameter(Mandatory=$True)]
[ValidateScript({Test-Path $_})]
[string] $Path,
[Parameter(Mandatory=$True)]
[ValidateNotNullOrEmpty()]
[string] $Key,
[Parameter(Mandatory=$True)]
[ValidateNotNullOrEmpty()]
[string]$Value,
[Switch] $ReplaceExistingValue,
[Switch] $ReplaceOnly
)
$regmatch= $("^($Key\s*=\s*)(.*)")
$regreplace=$('${1}'+$Value)
if ((Get-Content $Path) -match $regmatch)
{
If ($ReplaceExistingValue)
{
Write-Verbose "Replacing configuration Key ""$Key"" in configuration file ""$Path"" with Value ""$Value"""
(Get-Content -Path $Path) | ForEach-Object { $_ -replace $regmatch,$regreplace } | Set-Content $Path
}
else
{
Write-Warning "Key ""$Key"" found in configuration file ""$Path"". To replace this Value specify parameter ""ReplaceExistingValue"""
}
}
elseif (-not $ReplaceOnly)
{
Write-Verbose "Adding configuration Key ""$Key"" to configuration file ""$Path"" using Value ""$Value"""
Add-Content -Path $Path -Value $("`n" + $Key + "=" + $Value)
}
else
{
Write-Warning "Key ""$Key"" not found in configuration file ""$Path"" and parameter ""ReplaceOnly"" has been specified therefore no work done"
}
}
I've also added a function to read from the config file
Function Get-FileConfigurationValue()
{
[CmdletBinding()]
param(
[Parameter(Mandatory=$True)]
[ValidateScript({Test-Path $_})]
[string] $Path,
[Parameter(Mandatory=$True)]
[ValidateNotNullOrEmpty()]
[string] $Key,
[Parameter(Mandatory=$False)]
[ValidateNotNullOrEmpty()]
[string]$Default=""
)
# Don't have spaces before key.
# To allow spaces, use "$Key\s*=\s*(.*)"
$regKey = $("^$Key\s*=\s*(.*)")
# Get only last time
$Value = Get-Content -Path $Path | Where {$_ -match $regKey} | Select-Object -last 1 | ForEach-Object { $matches[1] }
if(!$Value) { $Value=$Default }
Return $Value
}
function sed($filespec, $search, $replace)
{
foreach ($file in gci -Recurse $filespec | ? { Select-String $search $_ -Quiet } )
{
(gc $file) |
ForEach-Object {$_ -replace $search, $replace } |
Set-Content $file
}
}
Usage:
sed ".\*.config" "intranet-" "intranetsvcs-"

cloning multiple VMs in parallel with multithreaded PowerCLI

I've taken on the task of cloning a ton of VMs in VMware. Rather than clicking hundreds of times through the clone wizard, I'd like to automate this as much as possible.
I've got the template machine already configured and "sealed." Once it's cloned and powered on, the newly-cloned instance will boot up, sit there for a while while it syspreps, etc. This takes about 20 minutes or so.
I found a very nice script over on MSFT TechNet that does everything I need it to do. I've modified it a little bit so I don't have to change a value and re-save the script for each step of the process. Instead of the $Step counter throughout the script, I've simply replaced it with some Start-Sleep delays. At this point, it works fine and successfully clones all the machines that it reads in from a CSV file. Each machine takes about 35 minutes before it's ready to go (machine is moved to a different AD OU).
The only problem is it's running all serially, waiting for the entire process (clone, change VLAN, boot machine and wait for domain join, and move final machine object to a different AD OU) to finish before starting another clone.
What I'd really like to somehow is multithread it to make the whole operation faster. I've found in testing that cloning within vSphere starts to slow down once about five separate clone jobs are running, so I'd like to modify this script to run four clones (doing the whole workflow) at once.
Any ideas? I can paste the code if needed.
You can at max clone 8 vms in parallel from one template. If you run new-vm with -RunAsync. With -RunAsync The command returns immediately and the output consists of one or more Task objects.
if you want to clone multiple VMs Following should help. just loop it.
Write-host "Deploying VM " -ForegroundColor Green -NoNewline; Write-Host $vmname -ForegroundColor Yellow
get-OScustomizationspec $cs | get-OScustomizationNicMapping | set-OSCustomizationNicMapping -IpMode UseStaticIP -IpAddress $vm.IP -SubnetMask $vm.subnet -DefaultGateway $vm.gateway -Dns $vm.Dns1, $vm.Dns2
$vms = New-VM -Name $vm.Name -Location $vm.cluster -VMhost $vm.vmhost -Template $vm.template -Datastore $vm.datastore -OSCustomizationSpec $cs -confirm:$false **-RunAsync**
if ($vm1.error) {
Write-Host "Error in deploying $vmname" -ForegroundColor Red
}
The following is a script I wrote over the past couple of days that deploys a VM template to about 650 of our servers. It deploys it from 3 different VM Hosts in different data centers across the country. It deploys 5 from the Irving location, 15 from Plano, and 15 from Atlanta at the same time. It runs between 7PM and 6AM Mon-Fri, and all day Saturday and Sunday. It exits if it runs any other time.
I ran out of time when trying to figure out how to pass more than one parameter to a function when calling that function using Start-Job, so I just created a separate function for the three locations instead.
Using this script we were able to deploy a new RDC image to over 650 locations on nights and weekends in about a week.
param(
[Parameter(ValueFromPipelineByPropertyName=$true)]
[string]$InputFile = $null
)
Get-Module -ListAvailable VMware* | Import-Module | Out-Null
Import-Module ActiveDirectory
$Global:CompletedHosts = #()
$MAXVMHostCount = 50
$IrvingMaxJobs = 6
$PlanoMaxJobs = 15
$AtlantaMaxJobs = 15
Function Add-VMHosts() {
param(
[Parameter(Mandatory=$true)][int]$MAXVMHostCount,
[Parameter(Mandatory=$false)][string]$InputFile
)
$AllVMHosts = #()
If ($InputFile) {
$AllVMHosts = Get-Content $InputFile
}
Else {
$Jobs = (Get-Job).Name
If ($Jobs -ne $null) {
$Jobs = $Jobs.Trim("-TXINTATL")
}
ForEach ($Server in (Get-ADComputer -Server *************** -SearchBase "OU=************************" -Filter { Name -like "**********" })) {
If ($Server.Name.Substring(10,1) -eq "0") {
$IP = "10." + $Server.Name.Substring(11,1) + "."
}
Else {
$IP = "10." + $Server.Name.Substring(10,2) + "."
}
If ($Server.Name.Substring(12,2) -eq "00") {
$IP += "100"
}
ElseIf ($Server.Name.Substring(12,1) -eq "0") {
$IP += $Server.Name.Substring(13,1)
}
Else {
$IP += $Server.Name.Substring(12,2)
}
$IP += ".252"
If ($IP -notin $Global:CompletedHosts -and $IP -notin $Jobs) {
$AllVMHosts = $AllVMHosts + $IP
}
}
}
Connect-VIServer ******************** -User "********************" -Password "********************" | Out-Null
$CurrentVMHostCount = (Get-VMHost -Location (Get-Datacenter "Profit Centers")).Count
$HostCount = 0
ForEach ($VMHost in $AllVMHosts) {
If ($HostCount -ge ($MaxVMHostCount - $CurrentVMHostCount)) {
Break
}
Else {
$AddFailed = $false
$ConnectFailed = $false
$Test = $null
$Test = Get-VMHost $VMHost -ErrorAction SilentlyContinue
If (!$Test -and (Test-Connection $VMHost -Quiet)) {
Try {
Connect-VIServer $VMHost -User "********************" -Password "********************" -WarningAction SilentlyContinue | Out-Null
}
Catch {
$ConnectFailed = $true
}
If (!$ConnectFailed -and (Get-VMHost $VMHost -ErrorAction SilentlyContinue | Get-VM -ErrorAction SilentlyContinue | Where { $_.Name -like "*********************" }) -eq $null -and (Test-Connection $VMHost -Quiet)) {
Set-VMHost -VMHost $VMHost -LicenseKey "********************" | Out-Null
Disconnect-VIServer -Server $VMHost -Confirm:$false | Out-Null
Add-VMHost $VMHost -Location (Get-DataCenter -Name "Profit Centers") -User "********************" -Password "********************" -Force:$true -ErrorAction SilentlyContinue | Out-Null
Start-Sleep -Seconds 5
Write-Host "$VMHost added to vCenter successfully"
$myVMHost = Get-VMHost $VMHost
$myVMHost | Get-VirtualPortGroup | Get-NicTeamingPolicy | Set-NicTeamingPolicy -InheritLoadBalancingPolicy $true -InheritNetworkFailoverDetectionPolicy $true -InheritNotifySwitches $true -InheritFailback $true -InheritFailoverOrder $true -WarningAction SilentlyContinue | Out-Null
$myVMHost | Get-VirtualPortGroup | Get-SecurityPolicy | Set-SecurityPolicy -AllowPromiscuousInherited $true -ForgedTransmitsInherited $true -MacChangesInherited $true | Out-Null
ForEach ($PortGroup in (Get-VirtualPortGroup -VMHost $VMHost)) {
$netSys = Get-View (Get-VMHost -Name $VMHost).ExtensionData.ConfigManager.NetworkSystem
$spec = (Get-VirtualPortGroup -Name $PortGroup.Name -VMHost $VMHost).ExtensionData.Spec
$spec.Policy.ShapingPolicy.Enabled = $null
$netSys.UpdatePortgroup($PortGroup.Name,$spec)
}
$DisconnectedNICs = Get-VMHostNetworkAdapter -VMHost $VMHost -Physical | Where-Object { $_.BitRatePerSec -eq "0" }
If (($DisconnectedNICs.Count -gt 0)) {
If (($DisconnectedNICs.DeviceName).Contains("vmnic0")) {
$myVMHost | Get-VirtualSwitch -Name vSwitch0 | Get-NicTeamingPolicy | Set-NicTeamingPolicy -MakeNicActive vmnic1,vmnic0 | Out-Null
}
}
$HostCount++
}
ElseIf ($ConnectFailed) {
Write-Host "Failed to connect to $VMHost" -ForegroundColor Yellow
}
Else {
Write-Host "$VMHost already has RDC Image" -ForegroundColor Yellow
If ($VMHost.Name -notin $Global:CompletedHosts) {
$Global:CompletedHosts = $Global:CompletedHosts + $VMHost.Name
}
}
}
Else {
Write-Host "$VMHost already exists in vCenter" -ForegroundColor Yellow
}
}
}
Get-AlarmDefinition "Network uplink redundancy lost" -ErrorAction SilentlyContinue | Set-AlarmDefinition -Enabled $false | Out-Null
Get-AlarmDefinition "Network uplink redundancy lost" -ErrorAction SilentlyContinue | Set-AlarmDefinition -Enabled $true | Out-Null
Disconnect-VIServer -Server * -Confirm:$false
}
Function CopyVMToHostIrving([string]$VMHost) {
Connect-VIServer ******************** -User "********************" -Password "********************" | Out-Null
If ((Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-RDC-PC*" }) -eq $null) {
$NewVMName = "CED-RDC-PC" + (Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-DC-PC*" }).Name.Substring(9,4)
New-VM -VMHost $VMHost -Name $NewVMName -Datastore (Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-DC-PC*" } | Get-Datastore).Name -Template "W2k19Std-Template-TX" -OSCustomizationSpec "Windows Server 2019 Customizations" | Out-Null
Start-Sleep -Seconds 10
Start-VM $NewVMName | Out-Null
Start-Sleep -Seconds 5
If ((Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-RDC-PC*" }) -eq $null -or (Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-RDC-PC*" }).PowerState -eq “PoweredOff”) {
Exit
}
Write-Verbose -Message "Verifying that Customization for VM $NewVMName has started ..." -Verbose
While($True) {
$DCvmEvents = Get-VIEvent -Entity $NewVMName
$DCstartedEvent = $DCvmEvents | Where { $_.GetType().Name -eq "CustomizationStartedEvent" }
If ($DCstartedEvent) {
Break
}
Else {
Start-Sleep -Seconds 5
}
}
Write-Verbose -Message "Customization of VM $NewVMName has started. Checking for Completed Status......." -Verbose
While($True) {
$DCvmEvents = Get-VIEvent -Entity $NewVMName
$DCSucceededEvent = $DCvmEvents | Where { $_.GetType().Name -eq "CustomizationSucceeded" }
$DCFailureEvent = $DCvmEvents | Where { $_.GetType().Name -eq "CustomizationFailed" }
If ($DCFailureEvent) {
Write-Warning -Message "Customization of VM $NewVMName failed" -Verbose
Break
}
If ($DCSucceededEvent) {
Break
}
Start-Sleep -Seconds 5
}
Write-Verbose -Message "Customization of VM $NewVMName Completed Successfully!" -Verbose
Start-Sleep -Seconds 30
Write-Verbose -Message "Waiting for VM $NewVMName to complete post-customization reboot." -Verbose
Wait-Tools -VM $NewVMName -TimeoutSeconds 500 | Out-Null
Start-Sleep -Seconds 30
Shutdown-VMGuest $NewVMName -Confirm:$false | Out-Null
}
Disconnect-VIServer -Server * -Confirm:$false
}
Function CopyVMToHostPlano([string]$VMHost) {
Connect-VIServer ******************** -User "********************" -Password "********************" | Out-Null
If ((Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-RDC-PC*" }) -eq $null) {
$NewVMName = "CED-RDC-PC" + (Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-DC-PC*" }).Name.Substring(9,4)
New-VM -VMHost $VMHost -Name $NewVMName -Datastore (Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-DC-PC*" } | Get-Datastore).Name -Template "W2k19Std-Template-INT" -OSCustomizationSpec "Windows Server 2019 Customizations" | Out-Null
Start-Sleep -Seconds 10
Start-VM $NewVMName | Out-Null
Start-Sleep -Seconds 5
If ((Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-RDC-PC*" }) -eq $null -or (Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-RDC-PC*" }).PowerState -eq “PoweredOff”) {
Exit
}
Write-Verbose -Message "Verifying that Customization for VM $NewVMName has started ..." -Verbose
While($True) {
$DCvmEvents = Get-VIEvent -Entity $NewVMName
$DCstartedEvent = $DCvmEvents | Where { $_.GetType().Name -eq "CustomizationStartedEvent" }
If ($DCstartedEvent) {
Break
}
Else {
Start-Sleep -Seconds 5
}
}
Write-Verbose -Message "Customization of VM $NewVMName has started. Checking for Completed Status......." -Verbose
While($True) {
$DCvmEvents = Get-VIEvent -Entity $NewVMName
$DCSucceededEvent = $DCvmEvents | Where { $_.GetType().Name -eq "CustomizationSucceeded" }
$DCFailureEvent = $DCvmEvents | Where { $_.GetType().Name -eq "CustomizationFailed" }
If ($DCFailureEvent) {
Write-Warning -Message "Customization of VM $NewVMName failed" -Verbose
Break
}
If ($DCSucceededEvent) {
Break
}
Start-Sleep -Seconds 5
}
Write-Verbose -Message "Customization of VM $NewVMName Completed Successfully!" -Verbose
Start-Sleep -Seconds 30
Write-Verbose -Message "Waiting for VM $NewVMName to complete post-customization reboot." -Verbose
Wait-Tools -VM $NewVMName -TimeoutSeconds 500 | Out-Null
Start-Sleep -Seconds 30
Shutdown-VMGuest $NewVMName -Confirm:$false | Out-Null
}
Disconnect-VIServer -Server * -Confirm:$false
}
Function CopyVMToHostAtlanta([string]$VMHost) {
Connect-VIServer ******************** -User "********************" -Password "********************" | Out-Null
If ((Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-RDC-PC*" }) -eq $null) {
$NewVMName = "CED-RDC-PC" + (Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-DC-PC*" }).Name.Substring(9,4)
New-VM -VMHost $VMHost -Name $NewVMName -Datastore (Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-DC-PC*" } | Get-Datastore).Name -Template "W2k19Std-Template-ATL" -OSCustomizationSpec "Windows Server 2019 Customizations" | Out-Null
Start-Sleep -Seconds 10
Start-VM $NewVMName | Out-Null
Start-Sleep -Seconds 5
If ((Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-RDC-PC*" }) -eq $null -or (Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-RDC-PC*" }).PowerState -eq “PoweredOff”) {
Exit
}
Write-Verbose -Message "Verifying that Customization for VM $NewVMName has started ..." -Verbose
While($True) {
$DCvmEvents = Get-VIEvent -Entity $NewVMName
$DCstartedEvent = $DCvmEvents | Where { $_.GetType().Name -eq "CustomizationStartedEvent" }
If ($DCstartedEvent) {
Break
}
Else {
Start-Sleep -Seconds 5
}
}
Write-Verbose -Message "Customization of VM $NewVMName has started. Checking for Completed Status......." -Verbose
While($True) {
$DCvmEvents = Get-VIEvent -Entity $NewVMName
$DCSucceededEvent = $DCvmEvents | Where { $_.GetType().Name -eq "CustomizationSucceeded" }
$DCFailureEvent = $DCvmEvents | Where { $_.GetType().Name -eq "CustomizationFailed" }
If ($DCFailureEvent) {
Write-Warning -Message "Customization of VM $NewVMName failed" -Verbose
Break
}
If ($DCSucceededEvent) {
Break
}
Start-Sleep -Seconds 5
}
Write-Verbose -Message "Customization of VM $NewVMName Completed Successfully!" -Verbose
Start-Sleep -Seconds 30
Write-Verbose -Message "Waiting for VM $NewVMName to complete post-customization reboot." -Verbose
Wait-Tools -VM $NewVMName -TimeoutSeconds 500 | Out-Null
Start-Sleep -Seconds 30
Shutdown-VMGuest $NewVMName -Confirm:$false | Out-Null
}
Disconnect-VIServer -Server * -Confirm:$false
}
$Functions = [scriptblock]::Create(#"
Function CopyVMToHostIrving { $Function:CopyVMToHostIrving([string]$myVMHost) }
Function CopyVMToHostPlano { $Function:CopyVMToHostPlano([string]$myVMHost) }
Function CopyVMToHostAtlanta { $Function:CopyVMToHostAtlanta([string]$myVMHost) }
"#)
$TotalHostNum = (Get-ADComputer -Server ******************** -SearchBase "OU=********************" -Filter { Name -like "*CED-SQL-PC*" }).Count
While ($Global:CompletedHosts.Count -lt $TotalHostNum) {
Connect-VIServer ******************** -User "********************" -Password "********************" | Out-Null
Write-Host "Removing completed hosts from vCenter..."
ForEach ($VMHost in (Get-VMHost -Location (Get-Datacenter "Profit Centers") | Where-Object { $_.Parent -ne "Upgrade Failures" })) {
If (((Get-VMHost $VMHost | Get-VM | Where { $_.Name -like "CED-RDC-PC*" }) -ne $null -and $VMHost.Name -notin (Get-Job -State Running).Name.Trim("-TXINTATL")) -or (Get-VMHost $VMHost).ConnectionState -ne "Connected") {
Remove-VMHost $VMHost -Confirm:$false | Out-Null
If ($VMHost.Name -notin $Global:CompletedHosts) {
$Global:CompletedHosts = $Global:CompletedHosts + $VMHost.Name
}
}
}
Write-Host "Adding additional hosts to vCenter..."
If ($InputFile) {
Add-VMHosts -MAXVMHostCount $MAXVMHostCount -InputFile $InputFile
}
Else {
Add-VMHosts -MAXVMHostCount $MAXVMHostCount
}
$VMHosts = (Get-VMHost -Location (Get-Datacenter "Profit Centers") | Where-Object { $_.Parent -ne "Upgrade Failures" })
Disconnect-VIServer -Server * -Confirm:$false
ForEach ($VMHost in $VMHosts) {
Write-Host "Checking if max job count has been reached..."
While ((Get-Job -State Running).Count -ge ($IrvingMaxJobs + $PlanoMaxJobs + $AtlantaMaxJobs)) {
If (((Get-Date).hour -ge 6 -and (Get-Date).hour -lt 18) -and (Get-Date).DayOfWeek -ne "Saturday" -and (Get-Date).DayOfWeek -ne "Sunday") {
Write-Host "Total count of hosts that new VM was copied to: $Global:CompletedHosts.Count"
Exit
}
Else {
Start-Sleep -Seconds 60
}
}
Write-Host "Removing completed jobs..."
ForEach ($Job in (Get-Job -State Completed)) {
If ($Job.Name.Trim("-TXINTATL") -notin $GlobalCompletedHosts) {
$Global:CompletedHosts = $Global:CompletedHosts + $Job.Name.Trim("-TXINTATL")
}
Remove-Job -Id $Job.Id
}
Write-Host "Starting jobs..."
If ((Get-Job | Where { $_.Name.Trim("-TXINTATL") -eq $VMHost.Name }) -eq $null -and $VMHost.Name -notin $Global:CompletedHosts) {
If ((Get-Job | Where { $_.Name -like "*-TX" }).Count -lt $IrvingMaxJobs) {
Write-Host "Starting job for $VMHost using Irving Source" -ForegroundColor Yellow
Start-Job -InitializationScript $Functions -Script { CopyVMToHostIrving($Args[0]) } -ArgumentList $VMHost.Name -Name ($VMHost.Name + "-TX") | Out-Null
}
ElseIf ((Get-Job | Where { $_.Name -like "*-INT" }).Count -lt $PlanoMaxJobs) {
Write-Host "Starting job for $VMHost using Plano Source" -ForegroundColor Yellow
Start-Job -InitializationScript $Functions -Script { CopyVMToHostPlano($Args[0]) } -ArgumentList $VMHost.Name -Name ($VMHost.Name + "-INT") | Out-Null
}
ElseIf ((Get-Job | Where { $_.Name -like "*-ATL" }).Count -lt $AtlantaMaxJobs) {
Write-Host "Starting job for $VMHost using Atlanta Source" -ForegroundColor Yellow
Start-Job -InitializationScript $Functions -Script { CopyVMToHostAtlanta($Args[0]) } -ArgumentList $VMHost.Name -Name ($VMHost.Name + "-ATL") | Out-Null
}
}
}
}