{"id":20156250,"url":"https://github.com/dsccommunity/psnativecmddevkit","last_synced_at":"2025-04-09T22:23:10.119Z","repository":{"id":72632286,"uuid":"278811737","full_name":"dsccommunity/PSNativeCmdDevKit","owner":"dsccommunity","description":"Module to help developing commands that call native commands and binaries and parses their output.","archived":false,"fork":false,"pushed_at":"2021-01-14T14:15:11.000Z","size":82,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-03-24T00:16:35.262Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PowerShell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dsccommunity.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-07-11T07:29:10.000Z","updated_at":"2024-09-01T23:06:25.000Z","dependencies_parsed_at":"2023-04-15T22:05:07.433Z","dependency_job_id":null,"html_url":"https://github.com/dsccommunity/PSNativeCmdDevKit","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dsccommunity%2FPSNativeCmdDevKit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dsccommunity%2FPSNativeCmdDevKit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dsccommunity%2FPSNativeCmdDevKit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dsccommunity%2FPSNativeCmdDevKit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dsccommunity","download_url":"https://codeload.github.com/dsccommunity/PSNativeCmdDevKit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248120823,"owners_count":21051026,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-13T23:38:10.591Z","updated_at":"2025-04-09T22:23:10.108Z","avatar_url":"https://github.com/dsccommunity.png","language":"PowerShell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PSNativeCmdDevKit\r\n\r\n[![Build Status](https://dev.azure.com/dsccommunity/PSNativeCmdDevKit/_apis/build/status/dsccommunity.PSNativeCmdDevKit?branchName=master)](https://dev.azure.com/dsccommunity/PSNativeCmdDevKit/_build/latest?definitionId=43\u0026branchName=master)\r\n![Azure DevOps coverage (branch)](https://img.shields.io/azure-devops/coverage/dsccommunity/PSNativeCmdDevKit/43/master)\r\n[![Azure DevOps tests](https://img.shields.io/azure-devops/tests/dsccommunity/PSNativeCmdDevKit/43/master)](https://dsccommunity.visualstudio.com/PSNativeCmdDevKit/_test/analytics?definitionId=43\u0026contextType=build)\r\n[![PowerShell Gallery (with prereleases)](https://img.shields.io/powershellgallery/vpre/PSNativeCmdDevKit?label=PSNativeCmdDevKit%20Preview)](https://www.powershellgallery.com/packages/PSNativeCmdDevKit/)\r\n[![PowerShell Gallery](https://img.shields.io/powershellgallery/v/PSNativeCmdDevKit?label=PSNativeCmdDevKit)](https://www.powershellgallery.com/packages/PSNativeCmdDevKit/)\r\n\r\nA set of functions to help develop \"Native Command Wrapper\" faster.\r\n\r\n## Native Command Wrapper helper functions\r\n\r\nWhen you create modules that wrap binary executables and parses their output, you follow a similar pattern.\r\n\r\nYou build the command and its parameters based on what you want to achieve, redirect the Error stream to the success stream, process the output with regex-fu, and desinterlace the error stream to have its own handling.\r\n\r\nIf you're on Linux or Mac, you might also want to handle Sudo when invoking those commands.\r\nSome command can run without sudo or not, dependencing on the parameters used. Maybe an all or nothing approach is not the best, or maybe you want to let the user specify what other user to sudo as when running some commands.\r\n\r\nThis module tries to address these use case and avoid copying the same source code to different modules.\r\n\r\n## Scenarios\r\n\r\n### Invoke Native Command\r\n\r\nWhether you cant to invoke `dpkg` on a Debian or `Choco.exe` on Windows, you will have the same approach.\r\n\r\nBuild the parameters you wish to use, add the executable, redirect the STDERR to STDOUT and process those streams (separately).\r\n\r\nAs an example, on Linux you could wrap the `lsb_release --all` command.\r\n\r\n```PowerShell\r\nfunction Get-LsbRelease {\r\n    [OutputType([PSCustomObject])]\r\n    [CmdletBinding()]\r\n    param\r\n    (\r\n    )\r\n\r\n    $properties = Invoke-NativeCommand -Executable 'lsb_release' -Parameters '--all' |\r\n        Get-PropertyHashFromListOutput -ErrorHandling {\r\n            switch -Regex ($_) {\r\n                'No\\sLSB\\smodules' { Write-Verbose $_ }\r\n                Default            { Write-Error \"$_\" }\r\n            }\r\n        }\r\n\r\n    [PSCustomObject]$properties | Add-Member -TypeName 'LsbRelease' -PassThru\r\n}\r\n```\r\n\r\nThe Invoke-NativeCommand tells which executable to invoke, and with what arguments.\r\nIn this example, we don't require sudo either, otherwise we\r\ncould have hadded the `-Sudo` parameter to `Invoke-NativeComand`.\r\n\r\n## Converting a list-formatted output to a Hash\r\n\r\nIn the example above, the output of the command is a list view of the properties retrieved:\r\n\r\n```bash\r\ngael@laptop:~$ lsb_release --all\r\nNo LSB modules are available.\r\nDistributor ID: Ubuntu\r\nDescription:    Ubuntu 18.04.4 LTS\r\nRelease:        18.04\r\nCodename:       bionic\r\n```\r\n\r\nThe command `Get-PropertyHashFromListOutput` is a helper function to help parsing key/values properties coming from STDOUT.\r\n\r\nThe message `No LSB modules are available.` is actually coming from STDERR.\r\n\r\neach line of the output that is not coming from STDERR, is of the form: `^\\s*(?\u003cproperty\u003e[\\w-\\s]*):\\s*(?\u003cval\u003e.*)`.\r\nYou can use a customised regex using the parameter `-Regex`.\r\n\r\nWhen steaming the output of the invocation to this function like this:  \r\n`Invoke-NativeCommand -Executable 'lsb_release' -Parameters '--all' |  Get-PropertyHashFromListOutput`\r\n\r\nThe command is creating a hashtable of Key/value properties, removing spaces and dashes, in this case the hashtable returned would be defined like this:\r\n\r\n```PowerShell\r\n@{\r\n    DistributorID   = 'Ubuntu'\r\n    Description     = 'Ubuntu 18.04.4 LTS'\r\n    Release         = '18.04'\r\n    Codename        = 'bionic'\r\n}\r\n```\r\n\r\nBecause the line output `No LSB modules are available.` is \r\ncoming from STDERR, it is not parsed by the regex.  \r\nInstead, the `-ErrorHandling` scriptblock will process each line of STDERR.\r\nIn this case, the line matching the regex `No\\sLSB\\smodules` will be displayed on the verbose stream, while every other line comming from STDERR will be written on the error stream.\r\n\r\n\u003e Note: multi-line properties behave slightly differently.\r\n\r\nWhen a property carries on to the second line, and does not match the regex, the entire line is added to the last property created.\r\n\r\nFor instance:\r\n```bash\r\n$ dpkg --status powershell\r\nPackage: powershell\r\nStatus: install ok installed\r\nPriority: extra\r\nSection: shells\r\nInstalled-Size: 154614\r\nMaintainer: PowerShell Team \u003cPowerShellTeam@hotmail.com\u003e\r\nArchitecture: amd64\r\nVersion: 7.0.2-1.ubuntu.18.04\r\nDepends: libc6, libgcc1, libgssapi-krb5-2, liblttng-ust0, libstdc++6, zlib1g, libssl1.0.0, libicu60\r\nDescription: PowerShell is an automation and configuration management platform.\r\n It consists of a cross-platform command-line shell and associated scripting language.\r\nLicense: MIT License\r\nVendor: Microsoft Corporation\r\nHomepage: https://microsoft.com/powershell\r\n```\r\n\r\nThe Description property value here whould be\r\n```\r\nPowerShell is an automation and configuration management platform.\r\nIt consists of a cross-platform command-line shell and associated scripting language.\r\n```\r\n\r\n\u003e Note: This bit of code could be improved, to look at the left padding of the previous property, and see if the padding increased.  \r\n\u003e PR welcomed\r\n\r\n## Code of Conduct\r\n\r\nThis project has adopted this [Code of Conduct](CODE_OF_CONDUCT.md).\r\n\r\n## Releases\r\n\r\nFor each merge to the branch `master` a preview release will be\r\ndeployed to [PowerShell Gallery](https://www.powershellgallery.com/).\r\nPeriodically a release version tag will be pushed which will deploy a\r\nfull release to [PowerShell Gallery](https://www.powershellgallery.com/).\r\n\r\n## Contributing\r\n\r\nPlease check out common DSC Community [contributing guidelines](https://dsccommunity.org/guidelines/contributing).\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdsccommunity%2Fpsnativecmddevkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdsccommunity%2Fpsnativecmddevkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdsccommunity%2Fpsnativecmddevkit/lists"}