Why does a script from PSGallery not have a Zone.Identifier stream? - powershell

A NuGet repository, such as PSGallery, is clearly a remote system. Why do scripts installed from there not have a Zone.Identifier stream?
PS C:\> Find-Script -Repository PSGallery -Name Test-RPC | Install-Script -Scope CurrentUser
Untrusted repository
You are installing the scripts from an untrusted repository. If you trust this repository, change its InstallationPolicy value by running the
Set-PSRepository cmdlet. Are you sure you want to install the scripts from 'https://www.powershellgallery.com/api/v2'?
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "N"): Y
PS C:\> Get-Item -Path $Env:USERPROFILE\Documents\WindowsPowerShell\Scripts\Test-RPC.ps1 -Stream *
PSPath : Microsoft.PowerShell.Core\FileSystem::C:\Users\lit\Documents\WindowsPowerShell\Scripts\Test-RPC.ps1::$DATA
PSParentPath : Microsoft.PowerShell.Core\FileSystem::C:\Users\lit\Documents\WindowsPowerShell\Scripts
PSChildName : Test-RPC.ps1::$DATA
PSDrive : C
PSProvider : Microsoft.PowerShell.Core\FileSystem
PSIsContainer : False
FileName : C:\Users\lit\Documents\WindowsPowerShell\Scripts\Test-RPC.ps1
Stream : :$DATA
Length : 7771
The question is:
How can I ensure that users with ExecutionPolicy of RemoteSigned will need to use the signature? How will PowerShell know it is a remote file without a Zone.Identifier stream?
Is there any reason that package providers, especially untrusted ones, should not create a Zone.Identifier stream?

Continuing from my comment.
Clear-Host
$Url = 'https://www.powershellgallery.com/packages/Test-RPC/1.0/Content/Test-RPC.ps1'
$output = 'C:\Temp\Test-RPC.ps1'
$ValidateFile = {
Try {Get-Item -Path $output -Stream Zone.Identifier -ErrorAction Stop}
Catch [System.Exception]
{
Write-Warning -Message 'Error'
$PSItem.Exception.Message
}
}
Remove-Item -Path $output -Force -ErrorAction SilentlyContinue
Invoke-WebRequest -Uri $url -OutFile $output
Remove-Item -Path $output -Force -ErrorAction SilentlyContinue
$wc = New-Object System.Net.WebClient
$wc.DownloadFile($url, $output)
& $ValidateFile
Remove-Item -Path $output -Force -ErrorAction SilentlyContinue
(New-Object System.Net.WebClient).DownloadFile($url, $output)
& $ValidateFile
Import-Module -Name BitsTransfer
Remove-Item -Path $output -Force -ErrorAction SilentlyContinue
Start-BitsTransfer -Source $url -Destination $output
& $ValidateFile
Remove-Item -Path $output -Force -ErrorAction SilentlyContinue
Start-BitsTransfer -Source $url -Destination $output -Asynchronous
& $ValidateFile
# Results
<#
WARNING: Error
Could not open the alternate data stream 'Zone.Identifier' of the file 'C:\Temp\Test-RPC.ps1'.
WARNING: Error
Could not open the alternate data stream 'Zone.Identifier' of the file 'C:\Temp\Test-RPC.ps1'.
WARNING: Error
Could not open the alternate data stream 'Zone.Identifier' of the file 'C:\Temp\Test-RPC.ps1'.
WARNING: Error
JobId DisplayName TransferType JobState OwnerAccount
----- ----------- ------------ -------- ------------
f5f04c93-4247-4095-8d9a-587b26d64d26 BITS Transfer Download Connecting 570A5E12-BA93-4\WDAGUtilityAccount
Cannot find path 'C:\Temp\Test-RPC.ps1' because it does not exist.
#>
Doing the aforementioned download using real curl.exe also does not add the internet ADS tag. Manually download curl.exe via your browser.
https://curl.se/windows
Check the ADS data, note the internet tag is there.
The download using real curl.exe, in cmd.exe
curl.exe -O https://curl.se/windows/dl-7.76.0/curl-7.76.0-win64-mingw.zip
Check the ADS data, not the internet tag is not there.
Lastly, as for this ...
How can I ensure that users with ExecutionPolicy of RemoteSigned.
As documented and publically stated by MSFT, EP's are not a security boundary and that was never their design.
RemoteSigned ExecutionPolicy:
• Allows scripts to run
• Requires that all scripts ***downloaded from the Internet*** must
be ***digitally signed by a publisher you specified as trusted***.
This includes scripts received via email and instant messaging
platforms.
• Will not require digital signing of scripts written on a local
computer
• May allow running of malicious scripts from other sources
They are there to prevent accidental code runs. EP's can easily be bypassed and that too is fully documented/demo'd
15 Ways to Bypass the PowerShell Execution Policy:
https://blog.netspi.com/15-ways-to-bypass-the-powershell-execution-policy
Detecting Offensive PowerShell Attack Tools:
https://adsecurity.org/?p=2604
One can open any script in the ISE/VSCode, etc., select all, and hit run and the EP has no control over that. EP, is for running scripts by name, meaning, calling from the consolehost, scheduled task, etc.
Nothing stops a user from opening the script, removing the sigblock, and saving the script with a new name, and running it or creating a blank script, copy the content from the clocked script, saving and running.
PowerShell risk management/Security controls/mitigation are all the normal network/client stuff as well as all about full enterprise logging, auditing, and early alerting/effect response when strangeness is seen/discovered.

Related

Remove alternative data stream using powershell

I'm trying to remove a bunch of OSX alternate data streams on an NTFS volume. However no matter what I try I cannot get Powershell to do it. Yes, I admit that my powershell is not great. Is anyone able to help?
Objective: Remove the ADS "AFP_AfpInfo" from any directory in the volume.
Current Code:
Get-ChildItem E:\ -Directory -Recurse | ForEach-Object {
$streams = Get-Content -Path $_ -Stream AFP_AfpInfo -ErrorAction SilentlyContinue
if ($streams) {
$streams | ForEach-Object {
try {
Remove-Item -Path "$($_.PSPath)" -Stream AFP_AfpInfo -Recurse -Force -ErrorAction Silentlycontinue
}
catch {
Write-Host "An error occurred: $($_.Exception.Message)"
}
}
}
}
Current error:
An error occurred: A parameter cannot be found that matches parameter name 'Stream'.
Note: Running Powershell 7.3
-Recurse and -Stream don't seem to go together even though in the documentation they appear in the same Parameter Sets. In this case -Recurse should be removed. GitHub Issue #9822 was submitted to add clarification to the Remove-Item doc.
Also, you're seeking for an exact stream, AFP_AfpInfo, so I don't see a need to enumerate $streams. Lastly, checking if a file or folder has an alternative stream should be done with Get-Item instead of Get-Content for efficiency.
As a final aside, the code must use the .Remove method from EngineIntrinsics to work, Remove-Item -Confirm:$false -Force will always ask for confirmation on folders, arguably a bug. Remove-Item should skip confirmation checks if -Stream is in use and -Confirm:$false -Force. GitHub issue #19154 was submitted to follow up on this.
$removeFunc = $ExecutionContext.InvokeProvider.Item.Remove
$targetStream = 'AFP_AfpInfo'
Get-ChildItem E:\ -Recurse -Directory | ForEach-Object {
if ($stream = $_ | Get-Item -Stream $targetStream -ErrorAction SilentlyContinue) {
try {
$removeFunc.Invoke($stream.PSPath, $false, $true, $true)
}
catch {
Write-Host "An error occurred: $($_.Exception.Message)"
}
}
}
Why are you not just using the Unblock-File cmdlet to remove ADS?
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/unblock-file?view=powershell-7.3
Description This cmdlet only works on the Windows and macOS platforms.
The Unblock-File cmdlet lets you open files that were downloaded from
the internet. It unblocks PowerShell script files that were downloaded
from the internet so you can run them, even when the PowerShell
execution policy is RemoteSigned. By default, these files are blocked
to protect the computer from untrusted files.
Before using the Unblock-File cmdlet, review the file and its source
and verify that it is safe to open.
Internally, the Unblock-File cmdlet removes the Zone.Identifier
alternate data stream, which has a value of 3 to indicate that it was
downloaded from the internet.
Get-Help -Name Unblock-FIle -Examples
NAME
Unblock-File
SYNOPSIS
Unblocks files that were downloaded from the internet.
------------------ Example 1: Unblock a file ------------------
PS C:\> Unblock-File -Path C:\Users\User01\Documents\Downloads\PowerShellTips.chm
-------------- Example 2: Unblock multiple files --------------
PS C:\> dir C:\Downloads\*PowerShell* | Unblock-File
------------- Example 3: Find and unblock scripts -------------
PS C:\> Get-Item * -Stream "Zone.Identifier" -ErrorAction SilentlyContinue
FileName: C:\ps-test\Start-ActivityTracker.ps1
See also Get-Item, Clear-Content and Remove-Item cmdlets use case:
Friday Fun with PowerShell and Alternate Data Streams
https://jdhitsolutions.com/blog/scripting/8888/friday-fun-with-powershell-and-alternate-data-streams
You could also just use the MSSysinternals tool to remove ADS as well in your PS code.
https://learn.microsoft.com/en-us/sysinternals/downloads/streams

How to Run script with admin rights to change execution policy

See below script:
I need to launch this script with admin rights embedded inside of the script to set execution policy to unrestricted and then at the end of the script set it back. From what I've found so far this is either not possible or very difficult to do. I'm hoping there is an easier way to do this. The users that will be running this script do not have admin rights on their PC's so they will not be able to elevate and manually run from inside of powershell.
Stop-process -Name OUTLOOK -ErrorAction SilentlyContinue -Force
Stop-process -Name communicator -ErrorAction SilentlyContinue -Force
Stop-process -Name lync -ErrorAction SilentlyContinue -Force
Stop-Process -Name UcMapi -ErrorAction SilentlyContinue -Force
Stop-Process -Name skypehost -ErrorAction SilentlyContinue -Force
Stop-Process -Name searchprotocolhost -ErrorAction SilentlyContinue -Force
$OstPath = "c:\users\$([environment]::username)"+ "\AppData" + "\local" + "\Microsoft" + "\Outlook"
$ost = get-ChildItem $OstPath | where { $_.Extension -eq ".ost"}
$ost | remove-Item -force
Start-Process Outlook
if (Test-Path 'C:\Program Files (x86)\Microsoft Office\office15\lync.exe')
{
Start-Process 'C:\Program Files (x86)\Microsoft Office\office15\lync.exe'
}
Else
{
write-host "Lync is not installed"
if (Test-Path 'C:\Program Files (x86)\Microsoft Office Communicator')
{
Start-Process 'C:\Program Files (x86)\Microsoft Office Communicator\communicator.exe'
}
Else
{
write-host "Communicator is not installed"
}
}
You can use:
$GBL_Username = "Here type your username"
$GBL_Password = ConvertTo-SecureString –String "Here type your password in plain text" –AsPlainText -Force
$GBL_Credential = New-Object –TypeName System.Management.Automation.PSCredential –ArgumentList $GBL_Username, $GBL_Password
Start-Process 'C:\Program Files (x86)\Microsoft Office\office15\lync.exe' -Credential $GBL_Credential
And use the variable $GBL_Credential with the second part (the execution of Office Comunicator)
A problem with this: the credential will show in plain text and, if someone try to edit the script with notepad, PowerShell ISE or other program, they can will see the passsword.
Have a good day.
From what I see in the script, there's no need to elevate. If this is only to overcome the ExecutionPolicy than your approach is wrong. ExecutionPolicy is there to prevent users run untrusted scripts. So far your script is one of those.
Correct way of doing it would be to sign your script with the certificate and set your ExecutionPolicy to Allsigned on all computers. Users will then only be able to run the signed scripts from now on.
If this is not possible, I see 2 options:
Users copy contents of the script and paste it into the powershell window
You set ExecutionPolicy to unrestricted. Keep in mind that users will still need to elevate if they try to do something serious, but for this script elevation is not necessary.
So all in all, ExecutionPolicy is there to prevent exactly what you are trying to do, so do not expect it will be easy to overcome. It's also not something that you turn off and on. You should think of what is acceptable for you and set it to appropriate level in your environment.

Powershell Popup Box not showing when installing through SCCM

Not sure how to fix it but I think i have a hunch on why
I have a powershell script installs an applications but before it kicks off it shows a msgbox that simply displays a message to the user
The script works perfectly when I run it manually and even running it as the System account through psexec works as well
However when deploying this through SCCM - Software center, it installs without displaying the msgbox..
Now I think it might be because its not showing in the context of the current logged in user.. but I would of thought running it through Psexec as system would not work either...
Can anyone help? I have deployed it as an application through sccm using this script:
<#
.Date: 01-Jun-2016
.Ansys 16.2 Install Script
# Set up some Variables
$workingDirectory = (split-path $myinvocation.mycommand.path -parent)
# Display a warning message before installation begins
Add-Type -AssemblyName Microsoft.VisualBasic
[Microsoft.VisualBasic.Interaction]::MsgBox('Ansys 16.2 takes over 30 mins to install. Please do not log out or shutdown your computer during the installation. You can continue working as normal while it is being installed. Once complete you will see in Software Center say "installed" next to Ansys 16.2.', 'OKOnly,SystemModal,Exclamation', 'Warning')
# ***** Install Application ******
Start-Process -FilePath "$WorkingDirectory\ANSYS162_WINX64_Disk1\setup.exe" -ArgumentList "-silent -disablerss -licserverinfo `"::licensing-b`"" -Wait -ErrorAction SilentlyContinue
Start-Sleep -s 3
# ***** Delete Shortcut and unlicensed products *******
Remove-Item "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\ANSYS 16.2\Uninstall ANSYS 16.2.lnk" -Force -ErrorAction SilentlyContinue
Remove-Item "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\ANSYS 16.2\ANSYS Icepak 16.2.lnk" -Force -ErrorAction SilentlyContinue
Remove-Item "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\ANSYS 16.2\Aqwa" -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\ANSYS 16.2\ACP" -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\ANSYS 16.2\ANSYS Client Licensing" -Recurse -Force -ErrorAction SilentlyContinue "#>
Make sure that you have checked "allow the user to interact with this program" option while deployment
click here to see how to set user interaction

Automate process of Disk Cleanup cleanmgr.exe without user intervention

I am developing a powershell script file which shall execute some disk cleanup without user intervention. The user shall not be able to configure anything.
When I run cleanmgr.exe /d c: sageset:1 a popup window appears to select files/folders to be cleaned(cleanup options).
This will create a registry entry containing the settings with the cleanup options and after this, you can run cleanmgr.exe /sagerun:1 which will actually execute the cleanup.
Is there a way to specify the cleanup options directly with powerhell/command line(without the need to manually select things to be deleted)?
The following Powershell script automates CleanMgr.exe. In this case, it removes temporary files and runs the Update Cleanup extension to purge superseded Service Pack Backup files (Windows 10 now does this automatically via a scheduled task). To automate other extensions, create a "StateFlags0001" property in the corresponding Registry key, as done in the New-ItemProperty lines. You will find the Registry key names in the "VolumeCaches" branch.
As far as being silent, this script attempts to start CleanMgr.exe in a hidden window. However, at some point CleanMgr spawns new processes which are visible and must be waited on separately.
Write-Host 'Clearing CleanMgr.exe automation settings.'
Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\*' -Name StateFlags0001 -ErrorAction SilentlyContinue | Remove-ItemProperty -Name StateFlags0001 -ErrorAction SilentlyContinue
Write-Host 'Enabling Update Cleanup. This is done automatically in Windows 10 via a scheduled task.'
New-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Update Cleanup' -Name StateFlags0001 -Value 2 -PropertyType DWord
Write-Host 'Enabling Temporary Files Cleanup.'
New-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Temporary Files' -Name StateFlags0001 -Value 2 -PropertyType DWord
Write-Host 'Starting CleanMgr.exe...'
Start-Process -FilePath CleanMgr.exe -ArgumentList '/sagerun:1' -WindowStyle Hidden -Wait
Write-Host 'Waiting for CleanMgr and DismHost processes. Second wait neccesary as CleanMgr.exe spins off separate processes.'
Get-Process -Name cleanmgr,dismhost -ErrorAction SilentlyContinue | Wait-Process
$UpdateCleanupSuccessful = $false
if (Test-Path $env:SystemRoot\Logs\CBS\DeepClean.log) {
$UpdateCleanupSuccessful = Select-String -Path $env:SystemRoot\Logs\CBS\DeepClean.log -Pattern 'Total size of superseded packages:' -Quiet
}
if ($UpdateCleanupSuccessful) {
Write-Host 'Rebooting to complete CleanMgr.exe Update Cleanup....'
SHUTDOWN.EXE /r /f /t 0 /c 'Rebooting to complete CleanMgr.exe Update Cleanup....'
}
The PowerShell logic provided below is dynamic and ready for use or automation with the sageset options all being selected and no user interaction being required. This was inspired by multiple answers and comments from this post.
Note: I've adjusted for my needs and used successfully without any issues on multiple remote and local Windows 10 systems in particular.
Run on Local System
Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\*' | % {
New-ItemProperty -Path $_.PSPath -Name StateFlags0001 -Value 2 -PropertyType DWord -Force
};
Start-Process -FilePath CleanMgr.exe -ArgumentList '/sagerun:1' ##-WindowStyle Hidden
Run on Remote System
$cred = Get-Credential "domain\administrator";
Invoke-Command -ComputerName "computer004" {
Process {
Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\*' | % {
New-ItemProperty -Path $_.PSPath -Name StateFlags0001 -Value 2 -PropertyType DWord -Force
};
Start-Process -FilePath CleanMgr.exe -ArgumentList '/sagerun:1' -WindowStyle Hidden
}
} -AsJob -Credential $cred
Supporting Resources
cleanmgr
Invoke-Command
-AsJob
Run the command as a background job on a remote computer.
Use this parameter to run commands that take an extensive time to complete.
Get-Credential
Automate process of Disk Cleanup cleanmgr.exe without user intervention
Creating a Disk Cleanup Handler
You can use cleanmgr /verylowdisk to silently automate all the cleanup steps.
The only solution I found is to manually set the registry values like this:
...
#Set StateFlags0012 setting for each item in Windows 8.1 disk cleanup utility
if (-not (get-itemproperty -path 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Active Setup Temp Folders' -name StateFlags0012 -ErrorAction SilentlyContinue)) {
set-itemproperty -path 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Active Setup Temp Folders' -name StateFlags0012 -type DWORD -Value 2
set-itemproperty -path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\BranchCache' -name StateFlags0012 -type DWORD -Value 2
set-itemproperty -path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Downloaded Program Files' -name StateFlags0012 -type DWORD -Value 2
...
see full example
I ran into the same issue. Researching the possible ways, I have found the following:
http://stealthpuppy.com/cleaning-up-and-reducing-the-size-of-your-master-image/
It shows how to create the sageset registry settings via cmd. You can then use the sagerun:# cmd. I have not tried it via script yet, but have validated that it works...
This script will get all the Volume Caches from the Registry, enable them to be cleaned and run the CLEANMGR.EXE for all caches.
$VolumeCachesRegDir = "hklm:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches"
$CacheDirItemNames = Get-ItemProperty "$VolumeCachesRegDir\*" | select -ExpandProperty PSChildName
$CacheDirItemNames |
%{
$exists = Get-ItemProperty -Path "$VolumeCachesRegDir\$_" -Name "StateFlags6553" -ErrorAction SilentlyContinue
If (($exists -ne $null) -and ($exists.Length -ne 0))
{
Set-ItemProperty -Path "$VolumeCachesRegDir\$_" -Name StateFlags6553 -Value 2
}
else
{
New-ItemProperty -Path "$VolumeCachesRegDir\$_" -Name StateFlags6553 -Value 0 -PropertyType DWord
}
}
Start-Sleep -Seconds 3
Write-Host 'Running CleanMgr.exe...'
Start-Process -FilePath CleanMgr.exe -ArgumentList '/sagerun:65535' -WindowStyle Hidden -PassThru
cls
Running CleanMgr.exe in a powershell script or by itself seems to work fine as long as you run it locally with an account that has local admin rights. But try running it remotely via any remote management tool or remote scripting command (Invoke-Command) and it does not run. You might see the process running on the remote system but it doesn't seem to cleanup anything and the process never ends. I would be interested if anyone has been able to get cleanmgr.exe to run remotely without any user interaction. E.G. ConfigMgr Right Click Tools, ConfigMgr App or PKG, Task Scheduler.

Powershell in NonInteractive mode

I use Octopus for our deployments. I have a problem with one of the Powershell scripts to control the deployment:
# stops running processes
$processes = #("Notepad",
"Firefox")
foreach ($process in $processes)
{
$prc = Get-Process -Name $process -ErrorAction SilentlyContinue
if (-not($prc -eq $null))
{
Write-Host "Stopping " $prc.ProcessName
Stop-Process -InputObject $prc -ErrorAction SilentlyContinue
}
}
The programs I try to stop are not the ones you see in the script above, but they represent what I am trying to do. Now the problem I have with it, is that it works well on one server, but not on another. Where it does not work, I get the error message:
Stop-Process : Windows PowerShell is in NonInteractive mode. Read and Prompt functionality is not available.
The script that works runs on Powershell 3.0, the one that does not work on Powershell 2.0. I cannot upgrade to Powershell 3.0 everywhere yet because the old servers run with Windows Server 2003. How can I make it work on PS 2.0?
Run with -Force:
Stop-Process -InputObject $prc -ErrorAction SilentlyContinue -Force
As C.B. suggested in the comment: -confirm:$false should also work. Rationale for this is as follows: -Confirm is a switch parameter. Switch parameters can only take arguments if you specify the parameter with a trailing colon and a value.
I just tried to use Remove-Item on the directory with children and got same message:
Remove-Item : PowerShell is in NonInteractive mode. Read and Prompt functionality is not available.
In my case -Recurse key has helped.