Powershell Script Can't Run Properly With Task Scheduler - node.js

I have an odd problem. I have a script that works fine when manually run it. I created a scheduled job in windows and run this script automatically. The script works fine until the last stage of script.
$deploymentfiles_mdm = Get-ChildItem 'D:\DeploymentTriggerApp\*'
Write-Host $deploymentfiles_mdm
$timestamp_app = Get-Date -Format o | ForEach-Object {$_ -replace ":", "."}
Write-Host $timestamp_app
$server = Get-Content 'C:\Users\Administrator\Desktop\Scripts\AutoDeployment\ProdMDMapps.txt'
$User = 'domain\user'
$SecurePassword = Get-Content C:\Users\Administrator\Desktop\Scripts\Password.txt | ConvertTo-SecureString
$UserCred = New-Object System.Management.Automation.PSCredential ($User, $SecurePassword)
if (Test-Path -Path $deploymentfiles_mdm)
{
do{
try
{
$ServerSessions = New-PSSession -ComputerName $server -Credential $UserCred -ErrorAction Stop
Write-Host ("$ServerSessions")
}
catch [Exception]
{
Write-Host("Credential is incorrect or password is expired. Either change credential and run CredentialEncryption.ps1 or communicate with dc admin to open expired password!")
}
}while(!$ServerSessions)
Copy-Item "D:\Deployment_Files\*.zip" -ToSession $ServerSessions -Destination "D:\Deployment_Files\" -ErrorAction SilentlyContinue
try{
Invoke-Command -Session $ServerSessions -ScriptBlock {
param($timestampApp)
$appPath = Get-ChildItem 'D:\MDM\live\bin\'
Expand-Archive -Path 'D:\Deployment_Files\*.zip' -DestinationPath 'D:\Deployment_Files\' -Force
Remove-Item -Path 'D:\Deployment_Files\*.zip'
$nodeProcess = Get-Process | Where-Object { $_.Name -eq "node"}
if($nodeProcess -Or $appPath)
{
Get-Process | Where-Object { $_.Name -eq "node"} | Select-Object -First 1 | Stop-Process -Force
New-Item -Path 'D:\Backups\' -Name $timestampApp -ItemType 'directory'
Get-ChildItem -Path "D:\MDM\live\bin\" -Recurse | Move-Item -Destination "D:\Backups\$timestampApp\"
}
Copy-Item "D:\Deployment_Files\bin" -Destination "D:\MDM\live\" -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item "D:\Deployment_Files\*" -Recurse -Force
Start-Job -ScriptBlock{ node D:\MDM\live\bin\main.js}
} -ArgumentList $timestamp_app
}
catch
{
$_.Exception.Message
}
}
Remove-Item D:\DeploymentTriggerApp\*
In section Start-Job -ScriptBlock{ node D:\MDM\live\bin\main.js} the script can't start the node process. When I manually run it, it runs without any problem.
Any suggestions for that? (The node process needed to be in background job. If any alternative commands to that, I can also try that solution)

Below line solved my problem.
Start-Job -ScriptBlock{& 'C:\Program Files\nodejs\node.exe' D:\MDM\live\bin\main.js}

Related

Device Not coming in MEM portal or are with partially Workload shifted. How fix it?

I Tried below PowerShell.
Created a Powershell Script:
DeleteEnrollment.PS1
## Create Log
Function Write-Log
{
Param
(
[string]$Message
)
$Logfilepath = "C:\ProgramData\Microsoft\CoMgmtFixLog"
$Logfile = "C:\ProgramData\Microsoft\CoMgmtFixLog\CoMgmtFixLog.log"
If (!(Test-Path $Logfilepath))
{
New-Item -ItemType Directory -Path $Logfilepath -Force | Out-Null
}
If (!(Test-Path $Logfile))
{
New-Item -ItemType File -Path $Logfile -Force | Out-Null
}
$Stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss")
$mgs = "$Stamp $Message"
Add-Content $Logfile -Value $mgs
}
## Create TimeStamp in Registry
Function Create-Timestamp
{
param
(
[String]$RegKeypath,
[String]$RegKeyName,
[String]$RegKeyValue
)
$ComgmtFixHive = 'HKLM:\SOFTWARE\Policies\Microsoft\CoMgmtFix'
$Step = "$ComgmtFixHive\$RegKeypath"
If (!(Test-Path $ComgmtFixHive))
{
New-Item -Path $ComgmtFixHive -Force | Out-Null
}
If(!(Test-Path $Step))
{
New-Item -Path $Step -Force | Out-Null
}
If($Step -and $RegKeyName -and $RegKeyValue)
{
New-ItemProperty -Path $Step -Name $RegKeyName -Value $RegKeyValue -PropertyType 'String' -force -ea SilentlyContinue | Out-Null
}
New-ItemProperty -Path $Step -Name 'ExecutionTimeStap' -Value (Get-Date).toString("yyyy/MM/dd HH:mm:ss") -PropertyType 'String' -force -ea SilentlyContinue | Out-Null
}
## Script Block ##
$Stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss")
Write-Log "=========== Begining of Log - $Stamp =========="
## Retrieving Enrollment GUID
(Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Provisioning\OMADM\Accounts\*' | select Pschildname).pschildname | Out-File -FilePath 'C:\ProgramData\Microsoft\CoMgmtFixLog\EnrollmentGUID.txt'
$DeviceEnrollmentID = Get-Content 'C:\ProgramData\Microsoft\CoMgmtFixLog\EnrollmentGUID.txt'
Write-Log "Collected Enrollment GUID : $DeviceEnrollmentID"
Create-Timestamp -RegKeypath 'GetEnrollmentID' -RegKeyName 'EnrollmentID' -RegKeyValue $DeviceEnrollmentID
If (Test-Path "HKLM:\SOFTWARE\Microsoft\EnterpriseResourceManager\Tracked\$DeviceEnrollmentID")
{
Remove-Item -Path HKLM:\SOFTWARE\Microsoft\EnterpriseResourceManager\Tracked\$DeviceEnrollmentID -Recurse -Force
Write-Log "Delected : `"HKLM:\SOFTWARE\Microsoft\EnterpriseResourceManager\Tracked\$DeviceEnrollmentID`" registry."
}
If (Test-Path "HKLM:\SOFTWARE\Microsoft\Enrollments\$DeviceEnrollmentID")
{
Remove-Item -Path HKLM:\SOFTWARE\Microsoft\Enrollments\$DeviceEnrollmentID -Recurse -Force
Write-Log "Delected : `"HKLM:\SOFTWARE\Microsoft\Enrollments\$DeviceEnrollmentID`" registry."
}
## Retrieve Scheduled tasks
Write-Log "Checking and deleting Enrollment Scheduled tasks."
Create-Timestamp -RegKeypath 'ScheduledTaskDeletion'
$AllSchdTasks = Get-ScheduledTask | where TaskPath -eq "\Microsoft\Windows\Enterprisemgmt\$DeviceEnrollmentID\"
ForEach ($AllSchdTask in $AllSchdTasks)
{
$taskname = $AllSchdTask.TaskName
Unregister-ScheduledTask -TaskPath $AllSchdTask.TaskPath -TaskName $taskname -Confirm:$false
Write-Log "Deleting : $taskname"
}
Start-Process "$PSScriptRoot\PsExec.exe" -ArgumentList "-is powershell.exe -command Remove-Item 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\Microsoft\Windows\EnterpriseMgmt\$DeviceEnrollmentID' -Recurse -Force" -WindowStyle Hidden
## Removing MDM Certificate
Write-Log "Finding and deleting MDM certificate"
Create-Timestamp -RegKeypath 'MDMCertificateDeletion'
gci cert:\LocalMachine\My -Recurse | Where {$_.Issuer -match 'Microsoft Intune MDM Device CA'} | Remove-Item -Force
$MDMcert = Get-ChildItem cert:\LocalMachine\My -Recurse | Where {$_.Issuer -match 'Microsoft Intune MDM Device CA'}
If($MDMcert)
{
Write-Log "MDM Certificate NOT Deleted"
}
Else
{
Write-Log "MDM Certificate Deleted"
}
## Retrieving existing users
Write-Log "Retrieving Existing user name and deleting Microsoft AAD broker plugin files."
Create-Timestamp -RegKeypath 'DeleteUserFiles'
$UserFolders = Get-ChildItem "C:\Users"
ForEach ($UserFolder in $UserFolders)
{
if ($UserFolder.Name -ne 'adiadmin')
{
if ($UserFolder.Name -ne 'Public')
{
if ($UserFolder.Name -ne 'Default')
{
$username = $UserFolder.Name
Write-Log "Deleting Microsoft.AAD.BrokerPlugin files from $username"
$msaadName = (Get-ChildItem "C:\Users\$username\AppData\Local\Packages" -Recurse -Force -Include Microsoft.AAD.BrokerPlugin* -ea SilentlyContinue).Name
Remove-Item -Path "C:\Users\$username\AppData\Local\Packages\$msaadName\Settings\*" -Force -Recurse -ea SilentlyContinue
Remove-Item -Path "C:\Users\$username\AppData\Local\Packages\$msaadName\AC\TokenBroker\Accounts\*" -Force -Recurse -ea SilentlyContinue
}
}
}
}
## Running dsregcmd /leave
Write-Log "Running dsregcmd /leave command"
Create-Timestamp -RegKeypath 'DsRegcmdLeave'
Start-Process -FilePath "dsregcmd.exe" -ArgumentList "/leave" -Verb RunAs
#.\dsregcmd.exe /leave
## Printing Reboot required regkey
Write-Log "Please restart you computer to proceed with next step."
Create-Timestamp -RegKeypath 'Reboot' -RegKeyName 'IsRebootRequired' -RegKeyValue 'Yes'
#Remove-Item -Path C:\temp\PsExec.exe -Force
Write-Log "=========== End of Log - $Stamp =========="
Created text file(Server.txt) with the device list having the issue.
Executed CoMgmtFix.Ps1 script which does all the work..
Issue in the above steps is I need to delete device from Azure AD manually. If there any way to delete the device entery from Azure AD via Script itself?
Tried the above stesp but need a way to delete device from Azure AD via Script itself.
To delete device from Azure AD:
Include RemoveAzureADDevice PowerShell script command directly.
Before running the command, you must call connect-AzureAD in PowerShell.
Remove-AzureADDevice -objectID <objectID>
To test, I created a virtual machine windows device in my environment and joined with Azure AD.
Get the object ID from AD joined VM properties by visiting Azure Active Directory -> Devices -> All Devices & search for the registered device.
Output:
Note: To remove an Azure AD joined device, you must have "administrative/owner" permissions under Roles & Assignments -> Azure Active Directory
Refer MsDoc

PowerShell multithreaded compress dirs

I have a rootDir with 3 dirs under it, I just want to compress each dir and listen the result by using multithreaded code, so I tried the following:
Set-Location "C:\test"
$sw = [Diagnostics.Stopwatch]::StartNew()
Get-Job | Remove-Job
$rootDirectory = $PWD
$dirs = $(Get-ChildItem -Path $rootDirectory -Directory).Name
# $dirs = d1, d2, d3
$sb = {
Param($init)
Compress-Archive -Path $init -DestinationPath "$init.zip" -CompressionLevel NoCompression
}
$jobs = #()
$dirs | ForEach-Object {
$jobs += Start-Job -ScriptBlock $sb -ArgumentList $_
}
Wait-Job -Job $jobs | Out-Null
Receive-Job -Job $jobs
I got
The path 'd1' either does not exist or is not a valid file system path.
+ CategoryInfo : InvalidArgument: (d1:String) [Compress-Archive], InvalidOperationException
+ FullyQualifiedErrorId : ArchiveCmdletPathNotFound,Compress-Archive
+ PSComputerName : localhost
if I run the compress command serially, not using the Start-Job, all seems to work.
The jobs don't inherit their working directory directory from your script. Put the Set-Location inside the scriptblock and pass the directory as a parameter:
$rootdir = 'C:\test'
...
$jobs = Get-ChildItem -Path $rootdir -Directory | ForEach-Object {
Start-Job -ScriptBlock {
Param($init, $dir)
Set-Location $dir
Compress-Archive -Path $init -DestinationPath "${init}.zip" -CompressionLevel NoCompression
} -ArgumentList $_, $rootdir
}
...
Better yet, pass the full path as the parameter, not just the name:
$rootdir = 'C:\test'
...
$jobs = Get-ChildItem -Path $rootdir -Directory | ForEach-Object {
Start-Job -ScriptBlock {
Param($init)
Compress-Archive -Path $init -DestinationPath "${init}.zip" -CompressionLevel NoCompression
} -ArgumentList $_.FullName
}
...

Execute SQLs in Parallel from directory

I am able to execute all the .SQL files from directory on to the server serially using below command. But, we want to execute all these files in parallel.
My code for serial execution -
$PSScriptRoot = 'Y:\test\'
$ServerName = $env:COMPUTERNAME
foreach ($f in Get-ChildItem -path $PSScriptRoot -Filter *.sql | sort-object
-desc )
{
invoke-sqlcmd -InputFile $f.fullname -ServerInstance $ServerName
}
You could use jobs to have them execute in the background:
foreach ($f in Get-ChildItem -path $PSScriptRoot -Filter *.sql | sort-object
-desc)
{
Start-Job -ScriptBlock { invoke-sqlcmd -InputFile $args[0].fullname -ServerInstance $args[1] } -ArgumentList $f, $ServerName
}
If there is any output you can collect it via:
Get-Job | Wait-Job | Receive-Job

PowerShell Mutex & Jobs

I'm trying to run a PowerShell file delete operation that deletes files based on specific parameters. So, the code goes like this:
$sb = {
Get-ChildItem -Path $SubFolder | Remove-ChildItem
if ($Error[0] -eq $null) {
$results = New-Object PSObject -Property #{
$Foldername = $Subfolder.Name
$TotalFiles = $SubFolder.(Count)
}
} else {
$errorresult = "Error deleting files from $($Subfolder.Name)"
}
#Error Mutex
$ErrorLogmutex = New-Object System.Threading.Mutex($false, "ErrorLogFileHandler")
$ErrorLogmutex.WaitOne()
Out-File -Append -InputObject $errorresult -FilePath $Errorlog
$ErrorLogmutex.ReleaseMutex()
#Success Mutex
$Successmutex = New-Object System.Threading.Mutex($false, "SuccessFileHandler")
$SuccessLogmutex.WaitOne()
Out-File -Append -InputObject $results -FilePath $successlog
$Successmutex.ReleaseMutex()
}
#Calling scriptblock in multi-thread count of 5
{
foreach ($Subfolder in $Folder) {
while ((Get-Job -State Running).Count -ge 5) {
Start-Sleep -Seconds 5
}
Start-Job -ScriptBlock $sb -ArgumentList $arguments | Out-Null
}
The script runs, able to see the results if I explicitly call out Receive-Job -Name JobID, but the output does not produce any log files as I would've thought it would.

using credentials to get-childitem on other server

I'm working on a script that uses get-childitem on the other server, but need to change it so it uses credentials of the local account on the other server to do that. When I was just using Active Directory to do that, I was saving the task in our scheduler with my AD login, and it was good on the other server, using the UNC path. But we decided to change it to the local login there recently and I'm getting an error message, trying to use net use. Does anyone know of a good way to do this with the UNC path instead? Or, any idea why the following is giving an error message?
function GetSecureLogin(){
$global:username = "stuff"
$global:password = get-content C:\filename.txt | convertto-securestring
}
function Cleanup([string]$Drive) {
try {
$deleteTime = -42
$now = Get-Date
**#this is saying cannot find path '\\name.na.xxx.net\20xServerBackup\V' name truncated**
Get-ChildItem -Path $Drive -Recurse -Force |Where-Object {$_.LastWriteTime -lt $limit} | Remove-Item -Force
}
Catch{
Write-Host "Failed"
}
}
#####################start of script####################
$share = '\\name.na.xxx.net\20xServerBackup\'
$TheDrive = '\\name.na.xxx.net\20xServerBackup\VMs\'
$global:password = ""
$global:username = ""
GetSecureLogin
net use $share $global:password /USER:$global:username
[array]$DriveArray = #(TheDrive)
try{
$i=0
for ($i = $DriveArray.GetLowerBound(0); $i -le $DriveArray.GetUpperBound(); $i++) {
$tempDrv = $DriveArray[$i]
Cleanup $tempDrv
}
}
catch [Exception] {
Write-Host $_.Exception.Message
}
As you can see, I started using the example at this link with net use, but it's not doing the trick to use credentials to access the other server. powershell unc path cred
I got it to work this way, with New-PSDrive as #robert.westerlund suggests above:
$DestPath = split-path "$Drive" -Parent #this gives format without slash at and and makes powerShell *very happy*
New-PSDrive -Name target -PSProvider FileSystem -Credential $global:cred -Root "$DestPath" | Out-Null
$temp1 = Get-ChildItem -Path target:\VMs\ -Recurse -Force | Where-Object { $_.LastWriteTime -lt $limit}
Get-ChildItem -Path $Drive -Recurse -Force | Where-Object { $_.LastWriteTime -lt $limit} | Remove-Item -Force
Remove-PSDrive target
I had to add the cred part like this too:
$global:cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $global:username, $global:password

Resources