Powershell: Bug in 7.0.0-rc.2: Register-ScheduledJob ScriptBlock parameter doesn't work

Created on 26 Jan 2020  Â·  27Comments  Â·  Source: PowerShell/PowerShell

Steps to reproduce

Register-ScheduledJob -Name test -ScriptBlock { Write-Output "test" } -RunNow                                                                                               

Expected behavior

Id         Name            JobTriggers     Command                                  Enabled
--         ----            -----------     -------                                  -------
1          test            0                Write-Output "test"                     True

Actual behavior

Register-ScheduledJob: Cannot bind parameter 'ScriptBlock'. Cannot convert the " Write-Output "test" " value of type "System.String" to type "System.Management.Automation.ScriptBlock".

Environment data

Name                           Value
----                           -----
PSVersion                      7.0.0-rc.2
PSEdition                      Core
GitCommitId                    7.0.0-rc.2
OS                             Microsoft Windows 10.0.18363
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0
Committee-Reviewed Issue-Question Resolution-Fixed

Most helpful comment

@mklement0 you are right that there is a loss of fidelity.

If you manually load the module, it does give a message:
"WARNING: Module PSScheduledJob is loaded in Windows PowerShell using WinPSCompatSession remoting session; please note that all input and output of commands from this module will be deserialized objects. If you want to load this module into PowerShell Core please use 'Import-Module -SkipEditionCheck' syntax."

The issue here is that commands in the module break in a non-actionable way. It would almost be better to NOT import these modules than to appear to succeed but have cmdlets that fail in a non-obvious way.

I do not think the current experience is one we want to go live with.

All 27 comments

Definitely a regression from Windows PowerShell. It sounds like it may be related to this behavior: #4218

The module is not Core compatible and is loaded by compatibility feature.
/cc @anmenaga

It may be being loaded via compatibility, it is still broken. To release like this is poor, and WILL generate further issues. It seems to me import-module should refuse to load modules that simply do not work and probably never will (unless msft teams wake up and redevelop them). Fortunately that list is pretty small.

Why not a unsupported.json file in the $pshome folder that lists those modules that are really not usable. Import module would then just not load them. That list could then be updatable as things improve.00

A workaround is to use remoting and run the command in a proper winrm session. The help text probably needs to explain that.

Just curious!

When you run the following command:

PS [573] > Get-Module -l ScheduledTasks


    Directory: C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules

ModuleType Version    PreRelease Name                                PSEdition ExportedCommands
---------- -------    ---------- ----                                --------- ----------------
Manifest   1.0.0.0               ScheduledTasks                      Core,Desk {Get-ScheduledTask, Set-ScheduledTask, …

PS [582] >

It show that module PSEdition "Core,Desk".

This is leading people to believe that this module will run in both Windows PowerShell and PowerShell 7.

If this is not true, my understanding is, this is a bug!

PS [582] > $PSVersionTable

Name                           Value
----                           -----
PSVersion                      7.0.0-rc.2
PSEdition                      Core
GitCommitId                    7.0.0-rc.2
OS                             Microsoft Windows 10.0.18363
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

PS [596] >

Good catch Max - you are right about the ScheduledTask I took a look at the module manifest for this module and it does indeed state this is a Core,Desktop based module. But that is not I suspect the issue.

But whatever, it's a very poor user experience and I am sure one that is highly likely to generate more issue reports.

Register-ScheduledJob comes from a _different_ module, namely PSScheduledTasks (note the PS prefix).

That module doesn't show as such in PS Core at all: Get-Module -l PSScheduledJob has no output.

I know little about this integration mechanism, but that a WinPS-only module's commands would implicitly be available is a double-edged sword, for technical reasons:

While convenient on the one hand, it is important for the user to know that a hidden powershell.exe process (WinPS) is being utilized to execute the command, which has two important implications:

  • Degraded performance

  • More importantly, _loss of type fidelity_ both on input and output, due to use of the serialization infrastructure (of necessity).

@mklement0 you are right that there is a loss of fidelity.

If you manually load the module, it does give a message:
"WARNING: Module PSScheduledJob is loaded in Windows PowerShell using WinPSCompatSession remoting session; please note that all input and output of commands from this module will be deserialized objects. If you want to load this module into PowerShell Core please use 'Import-Module -SkipEditionCheck' syntax."

The issue here is that commands in the module break in a non-actionable way. It would almost be better to NOT import these modules than to appear to succeed but have cmdlets that fail in a non-obvious way.

I do not think the current experience is one we want to go live with.

Looks like the implicit remoting layer isn't converting the scriptblock -> string back to scriptblock? cc @PaulHigin

@SteveL-MSFT, yes, that's why I linked to #4218, where @BrucePay stated that this behavior is by design:

Historically this is by design. Serializing scriptblocks with fidelity resulted in too many places where there was automatic code execution so to facilitate secure restricted runspaces, scriptblocks are always deserialized to strings.

Given that deserialization by itself shouldn't result in code execution, I've always been puzzled by this, so I wonder if it's time to revisit the issue; sounds like by (securely) fixing this behavior, a whole class of bugs relating to the WinPS compatibility feature may go away.

P.S.: It's good to hear that there's a warning when _manually_ importing modules exposed via the WinPS compatibility feature, but you may never see it, given that these modules are apparently auto-loaded.

This has nothing to do with implicit remoting.

Scheduled jobs were not supported in PowerShell Core, but now seem to be building in PS7. When was this added to PS7? None of the tests have been ported and the feature still appears not to work in Core.

Oh, I see this is loading the module via WinPS compatibility work.

cc @anmenaga

If scriptblocks are by-design not deserialized, then I don't see how we can support any cmdlets that accept scriptblocks via implicit remoting. If that is the case, then we could detect that a cmdlet accepts such parameter types and not import it or not generate a proxy for that parameterset. This will, of course, create it's own user experience problem.

we could detect that a cmdlet accepts such parameter types and not import it or not generate a proxy for that parameterset. This will, of course, create its own user experience problem.

Certainly preferable to the current situation.

However, what I was suggesting is to _investigate if changing the historical behavior is an option_, as it has always been an unexpected inconsistency that can cause problems in explicit end-user scenarios too.

I personally don't know enough about this, but based on the design-rationale quoted above, it sounds like we'd need to simply make sure that PowerShell-_internally_ no accidental execution occurs (not sure when and why that would happen).

From the _user_'s perspective, a script block should deserialize as such, and it is their responsibility, as always, to decide if and when to invoke it.

For old code that worked around the limitation, this change should have little no impact, given how [scriptblock] instances stringify:

# The following should be equivalent
[scriptblock]::create(" 'foo' ") # convert from string
[scriptblock]::create({ 'foo' }) # redundant conversion from script block, which old code may end up doing

Hypothetically, old code that tries to access [string] properties on a deserialized script block could break, however - hopefully, this falls into bucket 3.

Sorry! For some reason, I thought the cmdlet was part of the PSScheduledTasks module.
So, why did PSScheduledJob module missed the PowerShell 7 boat?

I understand that this module won't be ported cross-platform. I think it should be included in PowerShell 7.

I thought that the intention of running Windows Module in PowerShell Core was to make them compatible. Unless there are plans not to support PSScheduledJob module in the future.

:)

It is not just script blocks, the ScheduledJob classes (ScheduledJobDefinition, ScheduledJob, ScheduledJobTrigger, etc.) are not designed to work over remoting. I think this module will have to be disallowed for Windows PowerShell compatibility.

The remoting layer automatically passes script block string contents, and this is the right thing to do. A ScriptBlock object is far too complex to try and serialize/deserialize.

not designed to work over remoting

Good to know; perhaps an explicit exclusion list, as suggested by @doctordns above, is the way to go then.

I was too narrowly focused on the serialization issue, for which I've opened a new issue: #11698

Just briefly:

A ScriptBlock object is far too complex to try and serialize/deserialize.

That is not what I was suggesting - no change to the _serialization_ part is required - which is a simple _string_ representation inside a <SBK> element.

_Update_: However, $using: references wouldn't be supported this way.

The only change required is to call [scriptblock]::Create() on the serialized text _automatically_ on _deserialization_ -analogous to how it works when you pass a script block to Invoke-Command -ComputerName ... for remote execution.

I previously suggested making this feature (WinPS compatible) turned off by default because of a lot of issues and make it opt-in - user should explicitly enable a _cmdlet_ he want to get.

Standing back, PowerShell 7 needs a good baked in compatibility story. Otherwise, current Windows PowerShell users are not going to be interested. Not being able to use Best Practices, WSUS, AD Deployment, PSSehcduled jobs - may not be to most IT Pro's taste. This lack of support is a turn off to wider adoption.

I believe PowerShell 7 needs a good back-compat story. Turning this off as @iSazonov suggests is not the best one we can deliver.

But whatever, we need to decide what the RTM behaviour will be. We are getting close to RTM and unless this is locked down tight NOW, I fear an RC3 might be needed.

Turning this off as @iSazonov suggests is not the best one we can deliver.

Best is port all modules :-) Really there are a lot of incompatible modules and incompatible cmdlets. This is unpredictable if not ported, so the only reliable way is to turn on only what you need and test.

I agree with @doctordns

We need to bring this up in the next PowerShell Community Meeting.
This way it will be on their list.

:)

From my Windows Server 2019:

PS C:\install\publish> $Desktop=Get-Module -PSEdition Desktop -All -ListAvailable
PS C:\install\publish> $core=Get-Module -PSEdition Core -All -ListAvailable
PS C:\install\publish> $Desktop.Count
60
PS C:\install\publish> $core.Count
52

It is 87%. _It doubled in a year_! And this work continues.

I believe PowerShell 7 needs a good, strong, and workable implementation. ANY error message must be actionable and relevant to the task the IT Pro is trying to carry out with PowerShell.

We know some modules are not likely to be usable any time soon within PowerShell 7. The WSUS team, for example, have a huge job to get rid of SOAP and make their cmdlets do the work and to not reply on methods. With the benefit of hindsight, that design should never have gone forward, but such is life.

I am coming to the view that we have three classes of modules: Those that are native, those that work using PSCompat, and those that are 'broken' and are not usable directly from within PowerShell 7. Those that can not be used are the ones that present a problem. I also think we need a solution that enables "bad" modules to not be loaded and is flexible to change.

@PowerShell/powershell-committee reviewed this. We agreed to add a denyList in 7.0 to explicitly not allow importing this module via the Windows PowerShell compatibility transport. The denyList needs to be enforced whether the import is implicit or explicit using the -UseWindowsPowerShell switch.

When does this start to hit the Daily BUild?

@doctordns Next day after #11726 will be merged.

:tada:This issue was addressed in #11726, which has now been successfully released as v7.0.0-rc.3.:tada:

Handy links:

Was this page helpful?
0 / 5 - 0 ratings