Need help creating pipelined powershell commands

Discussion in 'Windows 10' started by johnye_pt, Aug 29, 2015.

  1. johnye_pt

    johnye_pt MDL Addicted

    Aug 26, 2010
    741
    377
    30
    #1 johnye_pt, Aug 29, 2015
    Last edited by a moderator: Apr 20, 2017
    I'm trying to create some powershell commands in Windows 10 to run from a batch in a single line, but I can't figure out how to do some of them because I'm a newbie at powershell. The purposes are:

    1. Remove App from user account within FOR cicle (working):
    Code:
    powershell.exe -command "get-AppxPackage *Microsoft.%%a* | Remove-AppxPackage"
    2. Remove App from system within FOR cicle (not working), tried something like this:
    Code:
    powershell.exe -command "Get-AppXProvisionedPackage -online | Where { $_.PackageName -Match 'Microsoft.%%a' } | Remove-AppxProvisionedPackage -online -PackageName $_.PackageName
    This says "Cannot bind argument to parameter 'PackageName' because it is null." But if I remove the last pipe, it outputs the correct object:
    Code:
    powershell.exe -command "Get-AppXProvisionedPackage -online | Where { $_.PackageName -Match 'Microsoft.%%a' }
    This is driving me nuts, I've been running around in circles for days and got nowhere, except for dozens of pages opens about powershell and still couldn't make the command work... I'm sure the solution is very simple, I just can't get there.

    EDIT: I'm trying to make it work from the command line first, so I'm using "3DBuilder" instead of "%%a" and I have the appx so I can reinstall it again.
     
  2. AceUK

    AceUK MDL Novice

    Feb 17, 2011
    21
    18
    0
    #2 AceUK, Aug 29, 2015
    Last edited by a moderator: Apr 20, 2017
    There's a quote mark missing at the end. :)

    Code:
    powershell.exe -command "Get-AppXProvisionedPackage -online | Where { $_.PackageName -Match 'Microsoft.3DBuilder' }"
    In the second command you don't need to add -online -PackageName $_.PackageName at the end because Remove-AppxProvisionedPackage gets the package name from Get-AppXProvisionedPackage. i.e.

    Code:
    powershell.exe -command "Get-AppXProvisionedPackage -online | Where { $_.PackageName -Match 'Microsoft.3DBuilder' } | Remove-AppxProvisionedPackage"
     
  3. tnx

    tnx MDL Expert

    Sep 2, 2008
    1,695
    267
    60
    Can I ask what a "Pipelined Powershell Command" is
     
  4. johnye_pt

    johnye_pt MDL Addicted

    Aug 26, 2010
    741
    377
    30
    #4 johnye_pt, Aug 30, 2015
    Last edited by a moderator: Apr 20, 2017
    (OP)
    Yes I missed a quote, but luckily powershell is a little more smart than batch and accepted the command anyway.

    About your suggestion, I tried it and it outputed a different error:
    Code:
    Remove-AppxProvisionedPackage : Cannot bind argument to parameter 'Path' because it is null.
    At line:1 char:94
    + ... geName -Match 'Microsoft.3dbuilder' } | Remove-AppxProvisionedPackage
    +                                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : InvalidData: (Microsoft.Dism....pxPackageObject:PSObject) [Remove-AppxProvisionedPackage], ParameterBindingValidationException
        + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.Dism.Commands.RemoveAppxProvisionedPackageCommand
    I don't think Remove-AppxProvisionedPackage accepts objects from the pipe, is it possible to assign the object to a variable within the pipe, then use that variable? I was thinking something like this (which also fails):
    Code:
    powershell.exe -command "Get-AppXProvisionedPackage -online | Where { $_.DisplayName -eq 'Microsoft.3dbuilder' } | %($var = $_) | Remove-AppxProvisionedPackage -Online -PackageName $var.Packagename"
    
    Remove-AppxProvisionedPackage : Cannot bind argument to parameter 'PackageName' because it is null.
    At line:1 char:157
    + ... | Remove-AppxProvisionedPackage -Online -PackageName $var.Packagename
    +                                                          ~~~~~~~~~~~~~~~~
        + CategoryInfo          : InvalidData: (:) [Remove-AppxProvisionedPackage], ParameterBindingValidationException
        + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.Dism.Commands.RemoveAppxProvisionedPacka
       geCommand

    Basically it's running the powershell commands piped in a single line instead of a script with several lines, then run it from the batch using powershell.exe -command "command 1 | command 2 | etc".
     
  5. tnx

    tnx MDL Expert

    Sep 2, 2008
    1,695
    267
    60
    Nice info..

    I think I am turning up late to the Powershell party.;)

    Without hijacking the thread, how do you make a .ps1 run from a bat\cmd.

    only just earlier I used Powershell to mount,unmount an install.wim
    It worked when I typed it into powershell but saving as a .ps1 did nothing.

    tn, always late :D
     
  6. AceUK

    AceUK MDL Novice

    Feb 17, 2011
    21
    18
    0
    #7 AceUK, Aug 30, 2015
    Last edited by a moderator: Apr 20, 2017
    When I tried it, it worked. :confused:

    Code:
    hxxp://i.imgur.com/FTG1PP9.png
    It does because I have used the following command to successfully remove apps from an offline Windows 10 image.

    Code:
    $Packages = 'Microsoft.3DBuilder','Microsoft.BingFinance','Microsoft.BingNews','Microsoft.BingSports','Microsoft.BingWeather','Microsoft.Getstarted','Microsoft.MicrosoftOfficeHub','Microsoft.MicrosoftSolitaireCollection',
                            'Microsoft.Office.OneNote','Microsoft.People','Microsoft.SkypeApp','Microsoft.Windows.Photos','Microsoft.WindowsAlarms','Microsoft.WindowsCamera','microsoft.windowscommunicationsapps','Microsoft.WindowsPhone',
                            'Microsoft.WindowsSoundRecorder','Microsoft.XboxApp','Microsoft.ZuneMusic','Microsoft.ZuneVideo' 
                            # Apps not removed: 'Microsoft.WindowsCalculator','Microsoft.WindowsMaps','Microsoft.WindowsStore'
                            
    Get-AppxProvisionedPackage -Path $MountFolder | Where-Object DisplayName -In $Packages | Remove-ProvisionedAppxPackage
    Since PowerShell is object-based it would be a bit unusual to have a cmdlet that doesn't accept objects from the pipeline.

    In your batch file try this command instead...

    Code:
    powershell.exe -command "$Packages = 'Microsoft.3DBuilder'; Get-AppxProvisionedPackage -Online | Where-Object DisplayName -In $Packages | Remove-ProvisionedAppxPackage" 
    Add additional packages to the $Packages variable.

    Code:
    powershell.exe -command "$Packages = 'Microsoft.3DBuilder','Microsoft.BingFinance'; Get-AppxProvisionedPackage -Online | Where-Object DisplayName -In $Packages | Remove-ProvisionedAppxPackage"
     
  7. johnye_pt

    johnye_pt MDL Addicted

    Aug 26, 2010
    741
    377
    30
    #8 johnye_pt, Aug 30, 2015
    Last edited by a moderator: Apr 20, 2017
    (OP)
    Yes, it also works for me without the Remove-ProvisionedAppxPackage at the end, I mentioned it in the first post. Adding it at the end is what originates the error.

    Tried them both, they also work without the Remove-ProvisionedAppxPackage or Remove-AppxProvisionedPackage at the end, adding it gets the same error:
    Code:
    Remove-AppxProvisionedPackage : Cannot bind argument to parameter 'Path' because it is null.
    At line:1 char:114
    + ... here-Object DisplayName -In $Packages | Remove-ProvisionedAppxPackage
    +                                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : InvalidData: (Microsoft.Dism....pxPackageObject:PSObject) [Remove-AppxProvisionedPackage], ParameterBindingValidationException
        + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.Dism.Commands.RemoveAppxProvisionedPackageCommand
    EDIT: OK, this is weird...

    Code:
    powershell.exe -command "$Packages = Get-AppxProvisionedPackage -Online | Where-Object DisplayName -eq 'Microsoft.3dbuilder' | ForEach-Object { Remove-AppxProvisionedPackage }"
    
    Remove-AppxProvisionedPackage : Parameter set cannot be resolved using the specified named parameters.
    At line:1 char:120
    + ... crosoft.3dbuilder' | ForEach-Object { Remove-AppxProvisionedPackage }
    +                                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : InvalidArgument: (:) [Remove-AppxProvisionedPackage], ParameterBindingException
        + FullyQualifiedErrorId : AmbiguousParameterSet,Microsoft.Dism.Commands.RemoveAppxProvisionedPackageCommand
    If I add -Online, it stops and asks for input:
    Code:
    powershell.exe -command "$Packages = Get-AppxProvisionedPackage -Online | Where-Object DisplayName -eq 'Microsoft.3dbuilder' | ForEach-Object { Remove-AppxProvisionedPackage -online }"
    
    cmdlet Remove-AppxProvisionedPackage at command pipeline position 1
    Supply values for the following parameters:
    PackageName:
    If I add $_.PackageName without the -PackageName parameter, this is what I get:
    Code:
    powershell.exe -command "$Packages = Get-AppxProvisionedPackage -Online | Where-Object DisplayName -eq 'Microsoft.3dbuilder' | ForEach-Object { Remove-AppxProvisionedPackage -online $_.PackageName }"
    Remove-AppxProvisionedPackage : A positional parameter cannot be found that accepts argument
    'Microsoft.3DBuilder_2015.720.2336.0_neutral_~_8wekyb3d8bbwe'.
    At line:1 char:120
    + ... rEach-Object { Remove-AppxProvisionedPackage -online $_.PackageName }
    +                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : InvalidArgument: (:) [Remove-AppxProvisionedPackage], ParameterBindingException
        + FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.Dism.Commands.RemoveAppxProvisionedPackageCommand
    So the PackageName IS there, it just won't work... aarrggg!
     
  8. wk-952

    wk-952 MDL Member

    Sep 2, 2012
    116
    287
    10
    #9 wk-952, Aug 30, 2015
    Last edited by a moderator: Apr 20, 2017
    AceUK was right at his second post but missed the "-Online" switch
    Code:
    powershell.exe -command "Get-AppXProvisionedPackage -online | Where { $_.DisplayName -Match 'Microsoft.SkypeApp' } | Remove-AppxProvisionedPackage -online"
    
    i tried something else that worked, which is setting the value of '$_.PackageName' to a var after the alias 'Where', then use the value of that var instead of '$_.PackageName'
    Code:
    powershell.exe -command "Get-AppXProvisionedPackage -online | Where { $_.DisplayName -Match 'Microsoft.BingFinance' } | %%{ $pName=$_.PackageName } ; echo [$pName]"
    
    replace the last echo command with
    Code:
    Remove-AppxProvisionedPackage -online -PackageName $pName
    
    in my case the echo command did output the correct value of the package name, so based on that i'm 100% sure it will work,
    also i want to explain that the double percentage marks '%%' are only essential if this whole long command is run from batch file (i guess you understand how batch file parser works),
    if it's from the CMD window directly then one '%' mark is needed

    EDIT:
    Also don't forget all credits goes to AceUK not me, i didn't do anything.

    Last note, if this is from a FOR loop then i would suggest using '%%~a' instead of %%a (make sure extensions are enabled)
    to remove the surrounding quotes (if there are any) from the package name when you're enumerating them.
    (if - by any chance - there are surrounding quotes on the package name, the batch parsing session of the current line
    won't go as expected and you might end up having the CMD treating the redirection pipe '|' as an effective token
    not as a normal char as how it is now)
     
  9. johnye_pt

    johnye_pt MDL Addicted

    Aug 26, 2010
    741
    377
    30
    #10 johnye_pt, Aug 30, 2015
    Last edited by a moderator: Apr 20, 2017
    (OP)
     
  10. AceUK

    AceUK MDL Novice

    Feb 17, 2011
    21
    18
    0
    #11 AceUK, Aug 30, 2015
    Last edited by a moderator: Apr 20, 2017
    @wk-952 was correct. I forgot to add the -Online switch. However once that's added it works perfectly for me. Here's proof...

    Code:
    Before: hxxp://i.imgur.com/lBEA6EM.png
    After: hxxp://i.imgur.com/dlWff5w.png
    Can you try either of the following?

    Code:
    powershell.exe -command "$Packages = 'Microsoft.3DBuilder'; Get-AppxProvisionedPackage -Online | Where-Object DisplayName -In $Packages | Remove-ProvisionedAppxPackage -Online"
    Code:
    powershell.exe -command "$Packages = 'Microsoft.3DBuilder','Microsoft.BingFinance'; Get-AppxProvisionedPackage -Online | Where-Object DisplayName -In $Packages | Remove-ProvisionedAppxPackage -Online"
    If it still doesn't work can you post your batch file or the relevant section that is running the PowerShell command(s)?
     
  11. johnye_pt

    johnye_pt MDL Addicted

    Aug 26, 2010
    741
    377
    30
    OK, just tried a few more commands and now even Remove-AppxProvisionedPackage was failing on its own so I went and checked if the folder app was really there: lo and behold, folder is not in "%programfiles%\WindowsApps" neither listed in Apps but is still in the output of Get-AppXProvisionedPackage!

    So the problem all along was Get-AppXProvisionedPackage returning an App that is actually not installed! And here I was thinking that putting it all together in a single line would make the batch that more simpler, and now I find out that even powershell has its quirks! I'm going to input a working line in another Windows 10 system TWICE and see what happens the 2nd time it runs, when Get-AppXProvisionedPackage is supposed to return nothing to Remove-AppxProvisionedPackage. At least it outputs errorlevel 0 when it works and not 0 when it doesn't work, so I can work around that if needed.