How to put a job on wait in powershell - powershell

HI every one I Have the following scripts which i am working on but not sure how to put a wait for a zip to finish and than move on to the next block of code. following are the two scripts which i am using. The first script is a backup script which is calling another script for zipping
$Date = Get-Date
$folder_date = $Date.ToString("yyyy-MM-dd_HHmm")
$backup_folder_name = 'c:\Russia\' + $folder_date
$V3_folder_name = 'C:\121RussiaScaled\products'
$Admin_folder_name = 'C:\inetpub\wwwroot\admin'
$Tablet_folder_name = 'C:\inetpub\wwwroot\tabl'
$Service_folder_name = 'C:\Russia\dll'
if (!(Test-Path -path $backup_folder_name)) {
New-Item $backup_folder_name -type directory
} # if (!(Test-Path -path D:Data))
if ((Test-Path -path $V3_folder_name)) {
Start-job -scriptblock {gi $V3_folder_name | .\Library\out-zip.ps1
$backup_folder_name\V3.zip $_}
Wait-job -Id $Job.Id
}
if ((Test-Path -path $Service_folder_name)) {
$Job = Start-job -scriptblock {gi $Service_folder_name | .\Library\out-zip.ps1
$backup_folder_name\Services.zip $_}
Wait-job -Id $Job.Id
}
if ((Test-Path -path $Admin_folder_name)) {
$Job = Start-job -scriptblock {gi $Admin_folder_name | .\Library\out-zip.ps1
$backup_folder_name\admin.zip $_}
Wait-job -Id $Job.Id
}
if ((Test-Path -path $Tablet_folder_name)) {
$Job = Start-job -scriptblock {gi $Tablet_folder_name | .\Library\out-zip.ps1
$backup_folder_name\tablet.zip $_}
Wait-job -Id $Job.Id
}
This is my out.zip script
$path = $args[0]
$files = $input
write-output $path
if (-not $path.EndsWith('.zip')) {$path += '.zip'}
if (-not (test-path $path)) {
set-content $path ("PK" + [char]5 + [char]6 + ("$([char]0)" * 18))
}
$ZipFile = (new-object -com shell.application).NameSpace($path)
$files | foreach {$zipfile.CopyHere($_.fullname)}
while using the above script i am getting an error "Start-Job missing an argument for the paratmeter script block."
or is there another way so that i can put a wait for these zips to finish one by one

Try
$Job = Start-Job -ScriptBlock .....
Wait-Job -Id $Job.Id
For the ScriptBlock error, try specifying the starting brace at the same line like:
$Job = Start-Job -ScriptBlock {
# Job code here
}

Related

Invoke-Command with timeout [duplicate]

This question already has answers here:
Getting an error when executing a nested ScriptBlock from Invoke-Command
(2 answers)
Closed 1 year ago.
Trying to create an invoke-command with a 10 second timeout incase one of my computers is in a zombie state and doesn't respond. Here's what I have so far below. But, one problem i'm having is that it doesn't behave like the normal invoke-command by reporting the output to the terminal as the command runs...
PS> Invoke_command_responsive -Computer pv3039 -ScriptBlock {gci -recurse -Path C:\ | out-host}
Cannot bind parameter 'ScriptBlock'. Cannot convert the "gci -recurse -Path C:\ | out-host" value of type "System.String" to type "System.Management.Automation.ScriptBlock".
+ CategoryInfo : InvalidArgument: (:) [Invoke-Command], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.InvokeCommandCommand
+ PSComputerName : localhost
Finished
Here's my code:
function invoke_command_responsive {
$start_time = Get-Date
$start_dir = better_resolve_path(".")
$watchdog = 60
$j = Start-Job -ScriptBlock {
set-location $using:start_dir | out-null
$iargs = $using:args
invoke-command #iargs | out-host
}
# Wait for Job to Complete or TIMEOUT!
while($true) {
if ($j.HasMoreData) {
Receive-Job $j
Start-Sleep -Milliseconds 200
}
$current = Get-Date
$time_span = $current - $start_time
if ($time_span.TotalSeconds -gt $watchdog) {
write-host "TIMEOUT!"
Stop-Job $j
break
}
if (-not $j.HasMoreData -and $j.State -ne 'Running') {
write-host "Finished"
break
}
}
Remove-Job $j
}
function better_resolve_path {
param([string]$path)
$pathfix = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($path)
return $pathfix
}
It kind of looks like it can't take a ScriptBlock from "using:"
Powershell just has trouble passing a scriptblock using "using:" syntax.
PS> invoke_command_responsive -Machine pv3040 -Cmd "get-location"
function invoke_command_responsive {
param(
[string]$Machine,
[string]$Cmd
)
$start_time = Get-Date
$start_dir = better_resolve_path(".")
$watchdog = 8 #seconds
[ScriptBlock]$sb = [ScriptBlock]::Create($opt_cmd)
$j = Start-Job -ScriptBlock {
set-location $using:start_dir | out-null
[ScriptBlock]$sb = [ScriptBlock]::Create($using:cmd)
invoke-command -Computer $using:Machine -ScriptBlock:$sb | out-host
}
# Wait for Job to Complete or TIMEOUT!
while($true) {
if ($j.HasMoreData) {
Receive-Job $j
Start-Sleep -Milliseconds 50
}
$current = Get-Date
$time_span = $current - $start_time
if ($time_span.TotalSeconds -gt $watchdog) {
write-host "TIMEOUT!"
Stop-Job $j
break
}
if (-not $j.HasMoreData -and $j.State -ne 'Running') {
write-host "Finished"
break
}
}
Remove-Job $j
}
function better_resolve_path {
param([string]$path)
$pathfix = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($path)
return $pathfix
}

Using Start-Job on script

Using a script in PowerShell to recursivly pass through all folders on multiple NAS boxes to display every folder with its full path in an Out-File.
Using the Get-FolderEntry script I found here.
Since I have multiple NAS boxes with more then 260 chars in the filename/pathlength I figured I'd use multithreading to speed the process up.
Code:
. C:\Users\mdevogea\Downloads\Get-FolderEntry.ps1
# list with the servers
$Computers = Get-Content C:\Users\mdevogea\Desktop\servers.txt
# scriptblock calling on get-FolderEntry
$sb = {
param ($Computer, $fname)
C:\Users\mdevogea\Downloads\Get-FolderEntry.ps1 -Path $Computer |
fl | Out-File -Append -Width 1000 -FilePath $fname
}
foreach($Computer in $Computers)
{
$name = $Computer.Replace("\", "")
$fname = $("C:\Users\mdevogea\Desktop\" + $name + ".txt")
#Get-FolderEntry -Path $Computer | fl | Out-File -Append -Width 1000 $fname
$res = Start-Job $sb -ArgumentList $Computer, $fname
}
# Wait for all jobs
Get-Job
while(Get-Job -State "Running")
{
Write-Host "Running..."
Start-Sleep 2
}
# Get all job results
Get-Job | Receive-Job | Out-GridView
So far:
I either get empty files with the correct naming of the file.
I get the correct named file with the code of Get-FolderEntry in it.
I get errors depend on what I pass along to the scriptblock.
In short, it's probably stupid but don't see it.
Found it eventually myself after some trial and error:
. C:\Users\mdevogea\Downloads\Get-FolderEntry.ps1
# list with the servers
$Computers = Get-Content C:\Users\mdevogea\Desktop\servers.txt
# scriptblock calling on get-FolderEntry
$sb = {
Param ($Computer, $fname)
. C:\Users\mdevogea\Downloads\Get-FolderEntry.ps1
(Get-FolderEntry -Path $Computer | fl | Out-File -Append -Width 1000 -FilePath $fname)
}
foreach ($Computer in $Computers)
{
$name = $Computer.Replace("\", "")
$fname = $("C:\Users\mdevogea\Desktop\" + $name + ".txt")
$res = Start-Job $sb -ArgumentList $Computer, $fname
}
# Wait for all jobs
Get-Job
while (Get-Job -State "Running")
{
Write-Host "Running..."
Start-Sleep 2
}
# Get all job results
Get-Job | Receive-Job | Out-GridView
Thanks a lot Ansgar for pointing my in the right direction!

Powershell export all detailed logging to csv file

I have inherited a script that is not working. I need to capture everything that would normally output to the console, including Success and Error entries from the script. This is only a small portion of the script, and it only captures errors. Any help would be appreciated on getting all output to the file instead of the console.
An example is the Write-Verbose "VERIFYING contact for $($User.WindowsEmailAddress)"
I know this is writing to the console, but I need it to write to the log that is defined at the very bottom of the script.
Catch
{Out-File -InputObject "$(Get-Date -Format MM.dd.yyyy-HH:mm:ss);$($WriteMode);ERROR;Target;$($targetUser.Split('#')[1]);$($User.WindowsEmailAddress);Update;;;Error updating user: $($Error[0])" -FilePath $LogFilePath -Append}
I hope this makes sense.
### UPDATES
ForEach ($User in $colUpdContact)
{
Write-Verbose "VERIFYING contact for $($User.WindowsEmailAddress)"
#Filter used to find the target contact object(s)
$strFilter = "WindowsEmailAddress -eq `"$($User.WindowsEmailAddress)`""
Try
{$colContacts2 = Invoke-Command -Session $targetSession -ScriptBlock {param ($strFilter) Get-Contact -Filter $strFilter} -ArgumentList $strFilter -ErrorAction Stop}
Catch
{Out-File -InputObject "$(Get-Date -Format MM.dd.yyyy-HH:mm:ss);$($WriteMode);ERROR;Target;$($targetUser.Split('#')[1]);$($User.WindowsEmailAddress);Find;;;Error getting contact: $($Error[0])" -FilePath $LogFilePath -Append}
ForEach ($Contact in $colContacts2)
{
#initialize update string and cmd string
$strUpdateContact = $null
$updateCmd = $null
$strWriteBack = $null
$writeBackCmd = $null
#Iterate through attributes and append to the strUpdateContact string if the attribute value has changed
ForEach ($Attrib in $arrAttribs)
{
If ($User.$Attrib -ne $Contact.$Attrib)
{
if($ReadOnly){
Add-Content -Path $readOnlyFilePath -Value " Changing $Attrib"
Add-Content -Path $readOnlyFilePath -Value " Before: $($Contact.$Attrib)"
Add-Content -Path $readOnlyFilePath -Value " After: $($User.$Attrib)"
}
$strUpdateContact += " -$($Attrib) `"$($User.$Attrib)`""
Out-File -InputObject "$(Get-Date -Format MM.dd.yyyy-HH:mm:ss);$($WriteMode);CHANGE;Target;$($targetUser.Split('#')[1]);$($User.WindowsEmailAddress);Update;$($Contact.$Attrib);$($User.$Attrib);" -FilePath $LogFilePath -Append
}
}
#Check if LegacyExchangeDN has been written back to User object
$mailContact = Invoke-Command -Session $targetSession -ScriptBlock {param ($contact) Get-MailContact $($contact.WindowsEmailAddress)} -ArgumentList $Contact -ErrorAction Stop
$x500 = "X500:$($mailContact.LegacyExchangeDN)"
$userRec = Invoke-Command -Session $sourceSession -ScriptBlock {param ($User) Get-Recipient $($User.WindowsEmailAddress)} -ArgumentList $User -ErrorAction Stop
if($UserRec.emailAddresses -notcontains $x500){
$userName = ($user.UserPrincipalName).Split('#')[0]
if($userName -eq "")
{
$userName = $user.SamAccountName
}
$strWriteBack = "Set-ADUser -Identity $userName -Add #{ProxyAddresses=`"$x500`"} -Server $sourceDC -Credential `$sourceDCCredential"
}
#If there is anything to update
If ($strUpdateContact.Length -gt 0)
{
Write-Verbose "Updating attributes for $($User.WindowsEmailAddress)"
#Prepend the command for the contact being modified
$strUpdateContact = "Set-Contact $($User.WindowsEmailAddress) " + $strUpdateContact
If ($ReadOnly)
{Add-Content -Path $readOnlyFilePath -Value $strUpdateContact}
Else
{
Try
{
#Create the complete command and invoke it
$updateCmd = "Invoke-Command -Session `$targetSession -ScriptBlock {$($strUpdateContact)}"
Invoke-Expression $updateCmd -ErrorAction Stop
}
Catch
{Out-File -InputObject "$(Get-Date -Format MM.dd.yyyy-HH:mm:ss);$($WriteMode);ERROR;Target;$($targetUser.Split('#')[1]);$($User.WindowsEmailAddress);Update;;;Error updating contact: $($Error[0])" -FilePath $LogFilePath -Append}
}
}
If ($strWriteBack){
Write-Verbose "Updating X500 for $($User.WindowsEmailAddress)"
Out-File -InputObject "$(Get-Date -Format MM.dd.yyyy-HH:mm:ss);$($WriteMode);CHANGE;Target;$($targetUser.Split('#')[1]);$($User.WindowsEmailAddress);Update;;$x500;" -FilePath $LogFilePath -Append
If($ReadOnly){
Add-Content -Path $readOnlyFilePath -Value $strWriteBack
}
else{
Try
{
Invoke-Expression $strWriteBack -ErrorAction Stop
}
Catch
{Out-File -InputObject "$(Get-Date -Format MM.dd.yyyy-HH:mm:ss);$($WriteMode);ERROR;Target;$($targetUser.Split('#')[1]);$($User.WindowsEmailAddress);Update;;;Error updating user: $($Error[0])" -FilePath $LogFilePath -Append}
}
}
}
}
Why you not use the Start-Transcript to output all the information into a log file, and then you can manually copy anything you want?
An example for the command:
Start-Transcript -Path $TranscriptOutputFile -Append -Force
#Your script; write-output 'something update';
Stop-Transcript
Everything output by write-output command will be appended into the log file.

PowerShell pass a switch to a function with Invoke-Command

I'm having some difficulties passing the switch -CleanFolders to a function by using Invoke-Command. I found this, but I don't really know how to implement it as it's not targeted to a function.
Calling my function like this works fine:
Delete-OldFiles $Target $OlderThanDays $Server -CleanFolders
Invoke-Command -ComputerName "$Server" -Authentication Credssp -Credential $Credentials -ScriptBlock ${Function:Delete-OldFiles} -ArgumentList ($Target, $OlderThanDays, $Server)
But this doesn't work at all:
Invoke-Command -ComputerName "$Server" -Authentication Credssp -Credential $Credentials -ScriptBlock ${Function:Delete-OldFiles} -ArgumentList ($Target, $OlderThanDays, $Server, -CleanFolders)
Full script:
#__________________________________________________________________________________________________________________________________
$ImportFile = "S:\Input\Scheduled Task\Auto_Clean.csv"
$Password = cat "S:\Input\pwd.txt" | ConvertTo-SecureString -Force
$UserName = "domain\me"
#__________________________________________________________________________________________________________________________________
# Scriptblock for running the function in a job
$JobFunc = {
# Function that removes files older than x days in all subfolders
Function Delete-OldFiles {
<#
.SYNOPSIS
Script to delete files and folders older than x days
.DESCRIPTION
Remove files older than x days in all subfolders and write success and failure actions to the logfile in "\\DEUSTHEIDIT02\Log\Scheduled Task\Auto_Clean\".
By default, empty foldes will be left behind and not deleted.
.PARAMETER Target
The path that will be recusively scanned for old files
.PARAMETER OlderThanDays
Filter for age of file, entered in days. Use 0 for all files to be removed
.PARAMETER CleanFolders
If this switch is specified folders that are older than 'OlderThanDays' and are empty will be removed. Default behaviour of this script is to leave empty folders behind.
.EXAMPLE
Delete-OldFiles -Target "\\grouphc.net\bnl\DEPARTMENTS\Brussels\CBR\SHARE\Target" -OlderThanDays "10"
Delete-OldFiles "\\grouphc.net\bnl\DEPARTMENTS\Brussels\CBR\SHARE\Target" "10"
Delete-OldFiles "E:\DEPARTMENTS\CBR\SHARE\Target" "10"
Description:
Deletes all files older than 10 days in the Target folder and all of its subfolders and write success and failure to the log.
.EXAMPLE
Delete-OldFiles "\\grouphc.net\bnl\DEPARTMENTS\Brussels\CBR\SHARE\Target" "10" -CleanFolders
Description:
Deletes all files older than 10 days and all empty folders in the Target folder and all of its subfolders and write success and failure to the log.
.NOTES
REQUIREMENTS Remote server:
PowerShell 2.0
As admin run 'Set-ExecutionPolicy RemoteSigned'
As amdin run 'Enable-WSManCredSSP -Role Server -Force'
REQUIREMENTS Script server:
Enable-WSManCredSSP -Role Client -DelegateComputer *.grouphc.net -Force
CHANGELOG
2014/05/06 Script born
2014/05/07 Added total runtime of the script to the logfile
2014/05/12 Added timestamps, fail and success messages to the logfile
2014/05/13 Added PowerShell 2.0 compatibility for Windows Server 2003
2014/05/13 Added remove empty directories
2014/05/14 Added comment section on top
2014/05/15 Added parameters to pass variables $Target and $OlderThanDays
2014/05/19 Added CSV input file for easy management
2014/05/20 Created function Delete-OldFiles and Delete-OldFolders
2014/05/22 Rewrote script for calling functions
2014/05/23 Added switch -CleanFolders
2014/06/02 Added password authentication for double hop
2014/06/03 Added loging capability to different files with timestamps
.AUTHOR
Me #>
[CmdletBinding(SupportsShouldProcess=$True)] # Add -WhatIf support for dry run
Param(
[Parameter(Mandatory=$True,Position=1)]
[ValidateScript({Test-Path $_})]
[String]$Target,
[Parameter(Mandatory=$True,Position=2)]
[Int]$OlderThanDays,
[Parameter(Mandatory=$False,Position=3)]
[String]$Server,
[switch]$CleanFolders
)
#__________________________________________________________________________________________________________________________________
# Create logfile with the correct name
# Gets date and reformats to be used in log filename
$TempDate = (get-date).ToString("dd-MM-yyyy")
# Reformats $Target so it can be used in the log filename
$TempFolderPath = $Target -replace '\\','_'
$TempFolderPath = $TempFolderPath -replace ':',''
$TempFolderPath = $TempFolderPath -replace ' ',''
# Combines the date and the path scanned into the log filename
$script:LogFile = "\\DEUSTHEIDIT02\Log\Scheduled Task\Auto_Clean\$Server - $TempFolderPath - $TempDate.log"
#__________________________________________________________________________________________________________________________________
# Check the version of PowerShell
if ($PSVersionTable.PSVersion.Major -ge "3") {
# PowerShell 3+ Remove files older than (FASTER)
Get-ChildItem -Path $Target -Recurse -File |
Where-Object { $_.CreationTime -lt (Get-Date).AddDays(-$OlderThanDays) } |
ForEach {
$Item = $_.FullName
Remove-Item $Item -Recurse -Force -ErrorAction SilentlyContinue
# Log succes/failure
$Timestamp = (Get-Date).ToShortDateString()+" | "+(Get-Date).ToLongTimeString()
if (Test-Path $Item) {
"$Timestamp | FAILLED: $Server $Item (IN USE)"
}
else {
"$Timestamp | REMOVED: $Server $Item"
}
} | Tee-Object $LogFile -Append }
Else {
# PowerShell 2 Remove files older than
Get-ChildItem -Path $Target -Recurse |
Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt (Get-Date).AddDays(-$OlderThanDays) } |
ForEach {
$Item = $_.FullName
Remove-Item $Item -Recurse -Force -ErrorAction SilentlyContinue
# Log succes/failure
$Timestamp = (Get-Date).ToShortDateString()+" | "+(Get-Date).ToLongTimeString()
if (Test-Path $Item) {
Write-Host "$Timestamp | FAILLED: $Server $Item (IN USE)"
"$Timestamp | FAILLED: $Server $Item (IN USE)"
}
else {
Write-Host "$Timestamp | REMOVED: $Server $Item"
"$Timestamp | REMOVED: $Server $Item"
}
} | Out-File $LogFile -Append }
#__________________________________________________________________________________________________________________________________
# Switch -CleanFolders deletes empty folders older than x days
if ($CleanFolders) {
# Check the version of PowerShell
if ($PSVersionTable.PSVersion.Major -ge "3") {
# PowerShell 3+ Remove empty folders older than (FASTER)
Get-ChildItem -Path $Target -Recurse -Force -Directory -ErrorAction SilentlyContinue |
Where-Object { $_.CreationTime -lt (Get-Date).AddDays(-$OlderThanDays) } |
Where-Object { (Get-ChildItem -Path $_.FullName -Recurse -Force -File) -eq $null } |
ForEach {
$Item = $_.FullName
Remove-Item $Item -Recurse -Force -ErrorAction SilentlyContinue
# Log succes/failure
$Timestamp = (Get-Date).ToShortDateString()+" | "+(Get-Date).ToLongTimeString()
if (Test-Path $Item) {
"$Timestamp | FAILLED: $Server $Item (IN USE)"
}
else {
"$Timestamp | REMOVED: $Server $Item"
}
} | Tee-Object $LogFile -Append
}
else {
# PowerShell 2 Remove empty folders older than
Get-ChildItem -Path $Target -Recurse -Force -ErrorAction SilentlyContinue |
Where-Object { $_.PSIsContainer -and (Get-ChildItem -Path $_.FullName -Recurse -Force | Where-Object { !$_.PSIsContainer }) -eq $null } |
Where-Object { $_.CreationTime -lt (Get-Date).AddDays(-$OlderThanDays) } |
ForEach {
$Item = $_.FullName
Remove-Item $Item -Recurse -Force -ErrorAction SilentlyContinue
# Log succes/failure
$Timestamp = (Get-Date).ToShortDateString()+" | "+(Get-Date).ToLongTimeString()
if (Test-Path $Item) {
Write-Host "$Timestamp | FAILLED: $Server $Item (IN USE)"
"$Timestamp | FAILLED: $Server $Item (IN USE)"
}
else {
Write-Host "$Timestamp | REMOVED: $Server $Item"
"$Timestamp | REMOVED: $Server $Item"
}
} | Out-File $LogFile -Append
}
}
}
}
#__________________________________________________________________________________________________________________________________
# Read input file and ignore all lines starting with #
$File = (Import-Csv -Path $ImportFile -Header "Server", "Target", "OlderThanDays" | Where { $_.Server -NotMatch "#" } )
#__________________________________________________________________________________________________________________________________
# If the UNC Path is provided we will run the script locally else it wil be run on the remote server as a job
Foreach ($_ in $File) {
# Set easy names
$Server = $_.Server
$Target = $_.Target
$OlderThanDays = $_.OlderThanDays
if ($Server -eq "UNC")
{
Write-Host "UNC Path detected: $Target, $OlderThanDays" -ForegroundColor Yellow
Start-Job -ScriptBlock {Param($Target, $OlderThanDays, $Server) Delete-OldFiles $Target $OlderThanDays $Server} -InitializationScript $JobFunc -ArgumentList ($Target, $OlderThanDays, $Server) -Name DelFiles
# Remove empty folders to: Delete-OldFiles $Target $OlderThanDays $Server -CleanFolders
}
else
{
Write-Host "Local path detected: $Server, $Target, $OlderThanDays" -ForegroundColor Cyan
$Credentials = New-Object System.Management.Automation.PSCredential -ArgumentList $UserName,$Password
$Credentials = New-Object System.Management.Automation.PSCredential -ArgumentList $UserName,$Password
Invoke-Command -ComputerName "$Server.grouphc.net" -Authentication Credssp -Credential $Credentials -ScriptBlock {$JobFunc; Delete-OldFiles $Target $OlderThanDays $Server} -ArgumentList ($Target, $OlderThanDays, $Server) #-AsJob -JobName DelFiles
#Invoke-Command -ComputerName "$Server.grouphc.net" -Authentication Credssp -Credential $Credentials -ScriptBlock {Delete-OldFiles $args[0] $args[1] $args[2] -CleanFolders:$args[3]} -ArgumentList ($Target, $OlderThanDays, $Server, $true) -AsJob -JobName DelFiles
# Invoke-Command -ComputerName "$Server.grouphc.net" -Authentication Credssp -Credential $Credentials -ScriptBlock ${Function:Delete-OldFiles} -ArgumentList ($Target, $OlderThanDays, $Server)
#Invoke-Command -ComputerName "$Server.grouphc.net" -Authentication Credssp -Credential $Credentials -ScriptBlock ${Function:Delete-OldFiles} -ArgumentList ($Target, $OlderThanDays, $Server) -AsJob -JobName DelFiles
#Invoke-Command -ComputerName "$Server.grouphc.net" -Authentication Credssp -Credential $Credentials -ScriptBlock {Delete-OldFiles $Target, $OlderThanDays, $Server} -ArgumentList ($Target, $OlderThanDays, $Server) #-AsJob -JobName DelFiles
#Invoke-Command -ComputerName "$Server.grouphc.net" -Authentication Credssp -Credential $Credentials -ScriptBlock {Function:Delete-OldFiles} -ArgumentList ($Target, $OlderThanDays, $Server) #-AsJob -JobName DelFiles
#Invoke-Command -ComputerName "$Server.grouphc.net" -Authentication Credssp -Credential $Credentials -ScriptBlock ${Function:Delete-OldFiles} -ArgumentList ($Target, $OlderThanDays, $Server)
#Invoke-Command -ComputerName "$Server.grouphc.net" -Authentication Credssp -Credential $Credentials -ScriptBlock {$JobFunc} -ArgumentList ($Target, $OlderThanDays, $Server) -AsJob -JobName DelFiles
#Invoke-Command -ComputerName "$Server.grouphc.net" -Authentication Credssp -Credential $Credentials -ScriptBlock ${Function:Delete-OldFiles} -ArgumentList ($Target, $OlderThanDays, $Server)
}
}
Thank you for your help.
Try like this:
$sb = {
function Delete-OldFiles {
#...
}
Delete-OldFiles $args[0] $args[1] $args[2] -CleanFolders:$args[3]
}
Invoke-Command -ComputerName $Server -Authentication Credssp `
-Credential $Credentials -ScriptBlock $sb `
-ArgumentList ($Target, $OlderThanDays, $Server, $true)

Not all of my PowerShell v2 jobs get run

I'm trying to use jobs to have simultaneous instances of PowerShell run, so that my script can finish faster. The scripts I'm calling are all independent, no need for mutual exclusion etc. Problem is that it will call five out of 50 scripts and then it will stop. The rest of the scripts never seem to run. Something wrong with wait-job? Also for some reason the five scripts that actually run seem to be executed twice so I get double output...
$Invocation = (Get-Variable MyInvocation -Scope 1).Value
$ScriptDir = Split-Path $Invocation.MyCommand
$ScriptDir -match '(?<content>.*\d)' | out-null
$MainDir = $matches['content']
$ScriptName = $MyInvocation.MyCommand.Name
$Items = Get-ChildItem -Path $MainDir | Where-Object {$_.mode -match "d"}
$jobMax = 4
$jobs = #()
$jobWork = {
param ($MyInput,$dir)
$command = "$dir\" + $MyInput.name + "\" + $MyInput.name + ".ps1"
Start-Process powershell.exe -argumentlist $command -WindowStyle Hidden #-wait
}
foreach ($Item in $Items) {
if ($jobs.Count -le $jobMax) {
$jobs += Start-Job -ScriptBlock $jobWork -ArgumentList $Item,$MainDir
} else {
$jobs | Wait-Job -Any
}
}
$jobs | Wait-Job
Edit: Also, since I'm using start-process powershell all the scripts run simultaneously(unless I enable -wait), without the need for start-job. I wanted to use jobs so that I can throttle. Maybe it's wrong logic that I have a job start a new instance of powershell?
Edit2: As I thought it was wrong to use start-job to start a new instance of poweshell. That way the job was done after it opened the new powershell instance, the actual script contents had nothing to do with the job's start and finish. Here is my fixed script :)
$Invocation = (Get-Variable MyInvocation -Scope 1).Value
$ScriptDir = Split-Path $Invocation.MyCommand
$ScriptDir -match '(?<content>.*\d)' | out-null
$MainDir = $matches['content']
$ScriptName = $MyInvocation.MyCommand.Name
$Items = Get-ChildItem -Path $MainDir | Where-Object {$_.mode -match "d"}
$maxJobs = 4
$jobs = #()
foreach ($Item in $Items) {
$command = "$MainDir\" + $Item.name + "\" + $Item.name + ".ps1"
$jobs += Start-Job -filepath $command -ArgumentList $MainDir,$Item
$running = #($jobs | ? {$_.State -eq 'Running'})
while ($running.Count -ge $maxJobs) {
$finished = Wait-Job -Job $jobs -Any
$running = #($jobs | ? {$_.State -eq 'Running'})
}
}
Wait-Job -Job $jobs > $null
I had to edit all my script so that I could pass the arguments as parameters, but now everything works fine. This thread was helpful Running multiple scriptblocks at the same time with Start-Job (instead of looping)
My guess is (after looking at your code) is that you will get only first 4 jobs started.
Jobs (even completed) do not disappear automagically. You need to clean them once they are completed (maybe Receive-Job's first). If you won't do that - PowerShell will spin $jobsMax jobs and once it's done - I would be really surprised to see any other "newcomers".
Add some Receive/Remove job logic and it should work better.
Also: as far as I can tell you are running scripts, so I would suggest using -File parameter on powershell.exe rather than -command.
HTH
Bartek