diff --git a/registry/Cargo.lock b/registry/Cargo.lock index 58896fbfa..618130ab0 100644 --- a/registry/Cargo.lock +++ b/registry/Cargo.lock @@ -47,7 +47,7 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -57,15 +57,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", - "windows-sys", + "windows-sys 0.52.0", ] +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + [[package]] name = "autocfg" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "base62" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f879ef8fc74665ed7f0e6127cb106315888fc2744f68e14b74f83edbb2a08992" + [[package]] name = "bitflags" version = "1.3.2" @@ -78,6 +90,16 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "bstr" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -130,6 +152,31 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + [[package]] name = "crossterm" version = "0.28.1" @@ -161,6 +208,18 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" version = "0.3.9" @@ -168,9 +227,51 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "fastrand" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "globset" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata 0.4.8", + "regex-syntax 0.8.5", ] +[[package]] +name = "globwalk" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" +dependencies = [ + "bitflags 1.3.2", + "ignore", + "walkdir", +] + +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" + [[package]] name = "heck" version = "0.5.0" @@ -183,12 +284,47 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "ignore" +version = "0.4.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" +dependencies = [ + "crossbeam-deque", + "globset", + "log", + "memchr", + "regex-automata 0.4.8", + "same-file", + "walkdir", + "winapi-util", +] + +[[package]] +name = "indexmap" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.11" @@ -207,6 +343,12 @@ version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +[[package]] +name = "libyml" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64804cc6a5042d4f05379909ba25b503ec04e2c082151d62122d5dcaa274b961" + [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -254,7 +396,16 @@ dependencies = [ "libc", "log", "wasi", - "windows-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "normpath" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8911957c4b1549ac0dc74e30db9c8b0e66ddcd6d7acc33098f4c63a64a6d7ed" +dependencies = [ + "windows-sys 0.59.0", ] [[package]] @@ -335,16 +486,36 @@ dependencies = [ "bitflags 2.6.0", ] +[[package]] +name = "ref-cast" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf0a6f84d5f1d581da8b41b47ec8600871962f2a528115b542b362d4b744931" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "regex" -version = "1.10.6" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.8", + "regex-syntax 0.8.5", ] [[package]] @@ -358,13 +529,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -375,9 +546,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "registry" @@ -385,7 +556,9 @@ version = "1.0.0" dependencies = [ "clap", "crossterm", + "regex", "registry 1.2.3", + "rust-i18n", "schemars", "serde", "serde_json", @@ -409,6 +582,60 @@ dependencies = [ "winapi", ] +[[package]] +name = "rust-i18n" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "039f57d22229db401af3458ca939300178e99e88b938573cea12b7c2b0f09724" +dependencies = [ + "globwalk", + "once_cell", + "regex", + "rust-i18n-macro", + "rust-i18n-support", + "smallvec", +] + +[[package]] +name = "rust-i18n-macro" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dde5c022360a2e54477882843d56b6f9bcb4bc62f504b651a2f497f0028d174f" +dependencies = [ + "glob", + "once_cell", + "proc-macro2", + "quote", + "rust-i18n-support", + "serde", + "serde_json", + "serde_yml", + "syn", +] + +[[package]] +name = "rust-i18n-support" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75d2844d36f62b5d6b66f9cf8f8cbdbbbdcdb5fd37a473a9cc2fb45fdcf485d2" +dependencies = [ + "arc-swap", + "base62", + "globwalk", + "itertools", + "lazy_static", + "normpath", + "once_cell", + "proc-macro2", + "regex", + "serde", + "serde_json", + "serde_yml", + "siphasher", + "toml", + "triomphe", +] + [[package]] name = "rustix" version = "0.38.37" @@ -419,7 +646,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -428,13 +655,23 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schemars" -version = "0.8.21" +version = "1.0.0-alpha.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" +checksum = "1848710f31190edab07d4dfee50b89cb4429a789c4aa9aa07356fbe59c59af52" dependencies = [ "dyn-clone", + "ref-cast", "schemars_derive", "serde", "serde_json", @@ -442,9 +679,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.21" +version = "1.0.0-alpha.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" +checksum = "09196e95ccdbafef196a660dc9380e322a222c73341162b611f0a8f32cc02375" dependencies = [ "proc-macro2", "quote", @@ -501,6 +738,32 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_yml" +version = "0.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e76bab63c3fd98d27c17f9cbce177f64a91f5e69ac04cafe04e1bb25d1dc3c" +dependencies = [ + "indexmap", + "itoa", + "libyml", + "log", + "memchr", + "ryu", + "serde", + "serde_json", + "tempfile", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -540,12 +803,24 @@ dependencies = [ "libc", ] +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + [[package]] name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "static_vcruntime" version = "2.0.0" @@ -569,6 +844,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + [[package]] name = "thiserror" version = "1.0.64" @@ -599,6 +887,40 @@ dependencies = [ "once_cell", ] +[[package]] +name = "toml" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tracing" version = "0.1.40" @@ -673,6 +995,17 @@ dependencies = [ "tracing-serde", ] +[[package]] +name = "triomphe" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef8f7726da4807b58ea5c96fdc122f80702030edc33b35aff9190a51148ccc85" +dependencies = [ + "arc-swap", + "serde", + "stable_deref_trait", +] + [[package]] name = "unicode-ident" version = "1.0.13" @@ -697,6 +1030,16 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -719,6 +1062,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -734,6 +1086,15 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-targets" version = "0.52.6" @@ -797,3 +1158,12 @@ name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] diff --git a/registry/Cargo.toml b/registry/Cargo.toml index b8c8a8f64..0d6eb2ed5 100644 --- a/registry/Cargo.toml +++ b/registry/Cargo.toml @@ -3,6 +3,11 @@ name = "registry" version = "1.0.0" edition = "2021" +[package.metadata.i18n] +available-locales = ["en"] +default-locale = "en" +load-path = "locales" + [profile.release] strip = true # optimize for size @@ -13,9 +18,11 @@ lto = true [dependencies] clap = { version = "4.5", features = ["derive"] } crossterm = "0.28" +regex = "1.11.0" registry = "1.2" -schemars = "0.8" -serde = "1.0" +rust-i18n = "3" +schemars = "1.0.0-alpha.15" +serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" thiserror = "1.0" tracing = { version = "0.1" } diff --git a/registry/locales/cli.yml b/registry/locales/cli.yml new file mode 100644 index 000000000..ae97ad820 --- /dev/null +++ b/registry/locales/cli.yml @@ -0,0 +1,91 @@ +_version: 2 +cli: + about: + en: Manage state of Windows registry + # config command help + config: + about: + en: Manage registry configuration. + args: + input: + help: + en: The registry JSON input. + what_if: + help: + en: Run as a what-if operation instead of applying the registry configuration. + get: + about: + en: Retrieve registry configuration. + set: + about: + en: Apply registry configuration. + delete: + about: + en: Delete registry configuration. + # query command help + query: + about: + en: Query a registry key or value. + args: + key_path: + help: + en: The registry key path to query. + value_name: + help: + en: The name of the value to query. + recurse: + help: + en: Recursively query subkeys. + # set command help + set: + about: + en: Set a registry key or value. + args: + key_path: + help: + en: The registry key path to set. + value: + help: + en: The value to set. + # remove command help + remove: + about: + en: Remove a registry key or value. + args: + key_path: + help: + en: The registry key path to remove. + value_name: + help: + en: The name of the value to remove. + recurse: + help: + en: Recursively remove subkeys. + # find command help + find: + about: + en: Find a registry key or value. + args: + key_path: + help: + en: The registry key path to start find. + find: + help: + en: The string to find. + recurse: + help: + en: Recursively find. + keys_only: + help: + en: Only find keys. + values_only: + help: + en: Only find values. + # schema command help + schema: + about: + en: Retrieve JSON schema. + args: + enhanced: + help: + en: Retrieve JSON schema enhanced for VS Code authoring and review. diff --git a/registry/locales/schemas.yml b/registry/locales/schemas.yml new file mode 100644 index 000000000..c66e98e24 --- /dev/null +++ b/registry/locales/schemas.yml @@ -0,0 +1,169 @@ +_version: 2 + +schema: + title: + en: Microsoft.Windows/Registry instance + description: + en: Manages Windows Registry keys and values. + markdownDescription: + en: |- + Each instance of the `Microsoft.Windows/Registry` resource manages a registry key or value. + You can use it to idempotently ensure that a registry key or value exists and set the data + for registry values. + # Properties + keyPath: + title: + en: Registry key path + description: + en: >- + Defines the path to the registry key to manage. Must be prefixed with a valid + hive identifier. Separate the paths with back slashes only. + markdownDescription: + en: |- + The `keyPath` property defines the path to the registry key an instance + of the resource manages. It must be prefixed with a valid hive identifier: + + | Identifier | Hive | + |:-------------------------------:|:----------------------| + | `HKCC` or `HKEY_CURRENT_CONFIG` | Current configuration | + | `HKCU` or `HKEY_CURRENT_USER` | Current user | + | `HKCR` or `HKEY_CLASSES_ROOT` | Classes root | + | `HKLM` or `HKEY_LOCAL_MACHINE` | Local machine | + | `HKU` or `HKEY_USERS` | Users | + + Specify the path to the registry key with backslashes (`\`), like + `HKCU\DSC\Properties\keyPath\Example`. If using JSON, ensure the + backlsashes are escaped, like `HKCU\\DSC\\Properties\\keyPath\\Example`. + patternErrorMessage: + en: >- + The value must begin with a valid hive identifier. Valid identifiers are: + + HKCC, HKEY_CURRENT_CONFIG, + HKCU, HKEY_CURRENT_USER + HKCR, HKEY_CLASSES_ROOT + HKLM, HKEY_LOCAL_MACHINE + HKU, and HKEY_USERS. + + metadata: + title: + en: Resource metadata + description: + en: Defines metadata returned by the resource. + markdownDescription: + en: |- + The `metadata` property defines metadata returned by the resource. The registry resource + doesn't support sending metadata input. It returns messages when invoked in what-if mode. + whatIf: + title: + en: What-if messages + description: + en: A list of messages returned by the resource when invoked in what-if mode. + markdownDescription: + en: >- + Contains a list of messages returned by the resource when invoked in what-if mode, as + with the `dsc config set --what-if` command. + valueName: + title: + en: Registry value name + description: + en: Defines the name of the registry value to manage. + markdownDescription: + en: |- + The `valueName` property defines the name of the registry value to manage. This value is + required when specifying value data. + valueData: + title: + en: Registry value data + description: + en: Defines the data for a registry value. + markdownDescription: + en: |- + Defines the data for a registry value. When you specify this value, you must also specify + the name of the registry value. + + Define the data as an object with a single property. The property name determines the data + type and the property value determines the data value. The following table lists the + available data types. + + | Property name | Data description | + |:--------------:|:-------------------------------------------------------------------| + | `String` | Defines the registry value as a static string. | + | `ExpandString` | Defines the registry value as a string with expandable references. | + | `MultiString` | Defines the registry value as an array of static strings. | + | `Binary` | Defines the registry value as an array of bytes. | + | `DWord` | Defines the registry value as an unsigned 32-bit integer. | + | `QWord` | Defines the registry value as an unsigned 64-bit integer. | + String: + title: + en: String value data + description: + en: Defines the registry value as a static string. + markdownDescription: + en: |- + When you define `valueData` with the `String` property, the resource sets the data for + the registry value as a static string. If the string contains any unexpanded references + to environment variables, such as `%PATH%`, the references are treated as literal + characters and aren't expandable.` + ExpandString: + title: + en: Expandable string value data + description: + en: Defines the registry value as a string with expandable references. + markdownDescription: + en: |- + When you define `valueData` with the `ExpandString` property, the resource sets the data + for the registry value as a string. If the string contains any unexpanded references to + environment variables, such as `%PATH%`, they're expandable. + MultiString: + title: + en: Multiple string value data + description: + en: Defines the registry value as an array of static strings. + markdownDescription: + en: |- + When you define `valueData` with the `MultiString` property, the resource sets the data + for the registry value as an array of static strings. You can specify the value as an + empty array, or as an array containing one or more strings. If any of the strings in the + array contain any unexpanded references to environment variables, such as `%PATH%`, the + references are treated as literal characters and aren't expandable. + Binary: + title: + en: Binary value data + description: + en: Defines the registry value as an array of bytes. + markdownDescription: + en: |- + When you define `valueData` with the `Binary` property, the resource sets the data for + the registry value as an array of bytes. You can specify the value as an empty array or + as an array containing the integer representation of one or more bytes. + DWord: + title: + en: DWord value data + description: + en: Defines the registry value as an unsigned 32-bit integer. + markdownDescription: + en: |- + When you define `valueData` with the `DWord` property, the resource sets the data for the + registry value as an unsigned 32-bit integer. + QWord: + title: + en: QWord value data + description: + en: Defines the registry value as an unsigned 64-bit integer. + markdownDescription: + en: |- + When you define `valueData` with the `QWord` property, the resource sets the data for the + registry value as an unsigned 64-bit integer. + exist: + title: + en: Exist + description: + en: Defines whether the instance should exist. + markdownDescription: + en: |- + The `_exist` property defines whether a registry key or value should exist. When this + property is `true`, the resource creates the registry key or value if it doesn't exist + during a `set` operation. When this property is `false`, the resource deletes the registry + key or value if it exists during a `set` operation. + + The default value is `true`. diff --git a/registry/src/args.rs b/registry/src/args.rs index a0521ec9f..0104ac8b6 100644 --- a/registry/src/args.rs +++ b/registry/src/args.rs @@ -4,7 +4,7 @@ use clap::{Parser, Subcommand}; #[derive(Parser)] -#[clap(name = "registry", version = "0.0.1", about = "Manage state of Windows registry", long_about = None)] +#[clap(name = "registry", version = "0.0.1", about = t!("cli.about").to_string(), long_about = None)] pub struct Arguments { #[clap(subcommand)] @@ -13,70 +13,73 @@ pub struct Arguments { #[derive(Debug, PartialEq, Eq, Subcommand)] pub enum ConfigSubCommand { - #[clap(name = "get", about = "Retrieve registry configuration.")] + #[clap(name = "get", about = t!("cli.config.get.about").to_string())] Get { - #[clap(short, long, required = true, help = "The registry JSON input.")] + #[clap(short, long, required = true, help = t!("cli.config.args.input.help").to_string())] input: String, }, - #[clap(name = "set", about = "Apply registry configuration.")] + #[clap(name = "set", about = t!("cli.config.set.about").to_string())] Set { - #[clap(short, long, required = true, help = "The registry JSON input.")] + #[clap(short, long, required = true, help = t!("cli.config.args.input.help").to_string())] input: String, - #[clap(short = 'w', long, help = "Run as a what-if operation instead of applying the registry configuration")] + #[clap(short = 'w', long, help = t!("cli.config.args.what_if.help").to_string())] what_if: bool, }, - #[clap(name = "delete", about = "Delete registry configuration.")] + #[clap(name = "delete", about = t!("cli.config.delete.about").to_string())] Delete { - #[clap(short, long, required = true, help = "The registry JSON input.")] + #[clap(short, long, required = true, help = t!("cli.config.args.input.help").to_string())] input: String, }, } #[derive(Debug, PartialEq, Eq, Subcommand)] pub enum SubCommand { - #[clap(name = "query", about = "Query a registry key or value.", arg_required_else_help = true)] + #[clap(name = "query", about = t!("cli.query.about").to_string(), arg_required_else_help = true)] Query { - #[clap(short, long, required = true, help = "The registry key path to query.")] + #[clap(short, long, required = true, help = t!("cli.query.args.key_path.help").to_string())] key_path: String, - #[clap(short, long, help = "The name of the value to query.")] + #[clap(short, long, help = t!("cli.query.args.value_name.help").to_string())] value_name: Option, - #[clap(short, long, help = "Recursively query subkeys.")] + #[clap(short, long, help = t!("cli.query.args.recurse.help").to_string())] recurse: bool, }, - #[clap(name = "set", about = "Set a registry key or value.")] + #[clap(name = "set", about = t!("cli.set.about").to_string())] Set { - #[clap(short, long, required = true, help = "The registry key path to set.")] + #[clap(short, long, required = true, help = t!("cli.set.args.key_path.help").to_string())] key_path: String, - #[clap(short, long, help = "The value to set.")] + #[clap(short, long, help = t!("cli.set.args.value.help").to_string())] value: String, }, - #[clap(name = "remove", about = "Remove a registry key or value.", arg_required_else_help = true)] + #[clap(name = "remove", about = t!("cli.remove.about").to_string(), arg_required_else_help = true)] Remove { - #[clap(short, long, required = true, help = "The registry key path to remove.")] + #[clap(short, long, required = true, help = t!("cli.remove.args.key_path.help").to_string())] key_path: String, - #[clap(short, long, help = "The name of the value to remove.")] + #[clap(short, long, help = t!("cli.remove.args.value_name.help").to_string())] value_name: Option, - #[clap(short, long, help = "Recursively remove subkeys.")] + #[clap(short, long, help = t!("cli.remove.args.recurse.help").to_string())] recurse: bool, }, - #[clap(name = "find", about = "Find a registry key or value.", arg_required_else_help = true)] + #[clap(name = "find", about = t!("cli.find.about").to_string(), arg_required_else_help = true)] Find { - #[clap(short, long, required = true, help = "The registry key path to start find.")] + #[clap(short, long, required = true, help = t!("cli.find.args.key_path.help").to_string())] key_path: String, - #[clap(short, long, required = true, help = "The string to find.")] + #[clap(short, long, required = true, help = t!("cli.find.args.find.help").to_string())] find: String, - #[clap(short, long, help = "Recursively find.")] + #[clap(short, long, help = t!("cli.find.args.recurse.help").to_string())] recurse: bool, - #[clap(long, help = "Only find keys.")] + #[clap(long, help = t!("cli.find.args.keys_only.help").to_string())] keys_only: bool, - #[clap(long, help = "Only find values.")] + #[clap(long, help = t!("cli.find.args.values_only.help").to_string())] values_only: bool, }, - #[clap(name = "config", about = "Manage registry configuration.", arg_required_else_help = true)] + #[clap(name = "config", about = t!("cli.config.about").to_string(), arg_required_else_help = true)] Config { #[clap(subcommand)] subcommand: ConfigSubCommand, }, - #[clap(name = "schema", about = "Retrieve JSON schema.")] - Schema, + #[clap(name = "schema", about = t!("cli.schema.about").to_string())] + Schema { + #[clap(short, long, help = t!("cli.schema.args.values_only.help").to_string())] + enhanced: bool, + }, } diff --git a/registry/src/config.rs b/registry/src/config.rs index a18fee2d1..2815f518f 100644 --- a/registry/src/config.rs +++ b/registry/src/config.rs @@ -3,33 +3,125 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use crate::schema::{get_registry_key_path_pattern, get_schema_uri}; #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)] pub enum RegistryValueData { + #[schemars( + title = t!("schema.valueData.String.title").to_string(), + description = t!("schema.valueData.String.description").to_string(), + extend( + "markdownDescription" = t!("schema.valueData.String.markdownDescription").to_string() + ) + )] String(String), + #[schemars( + title = t!("schema.valueData.ExpandString.title").to_string(), + description = t!("schema.valueData.ExpandString.description").to_string(), + extend( + "markdownDescription" = t!("schema.valueData.ExpandString.markdownDescription").to_string() + ) + )] ExpandString(String), + #[schemars( + title = t!("schema.valueData.Binary.title").to_string(), + description = t!("schema.valueData.Binary.description").to_string(), + extend( + "markdownDescription" = t!("schema.valueData.Binary.markdownDescription").to_string() + ) + )] Binary(Vec), + #[schemars( + title = t!("schema.valueData.DWord.title").to_string(), + description = t!("schema.valueData.DWord.description").to_string(), + extend( + "markdownDescription" = t!("schema.valueData.DWord.markdownDescription").to_string() + ) + )] DWord(u32), + #[schemars( + title = t!("schema.valueData.MultiString.title").to_string(), + description = t!("schema.valueData.MultiString.description").to_string(), + extend( + "markdownDescription" = t!("schema.valueData.MultiString.markdownDescription").to_string() + ) + )] MultiString(Vec), + #[schemars( + title = t!("schema.valueData.QWord.title").to_string(), + description = t!("schema.valueData.QWord.description").to_string(), + extend( + "markdownDescription" = t!("schema.valueData.QWord.markdownDescription").to_string() + ) + )] QWord(u64), } #[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)] #[serde(rename = "Registry", deny_unknown_fields)] +#[schemars( + title=t!("schema.title").to_string(), + description=t!("schema.description").to_string(), + extend( + "$id" = get_schema_uri(true), + "dependentRequired" = { "valueData": ["valueName"] }, + "markdownDescription" = t!("schema.markdownDescription").to_string() + ) +)] pub struct Registry { /// The path to the registry key. #[serde(rename = "keyPath")] + #[schemars( + title = t!("schema.keyPath.title").to_string(), + description = t!("schema.keyPath.description").to_string(), + required, + regex(pattern = get_registry_key_path_pattern()), + extend( + "markdownDescription" = t!("schema.keyPath.markdownDescription").to_string(), + "patternErrorMessage" = t!("schema.keyPath.patternErrorMessage").to_string(), + ) + )] pub key_path: String, /// The information from a config set --what-if operation. #[serde(rename = "_metadata", skip_serializing_if = "Option::is_none")] + #[schemars( + title = t!("schema.metadata.title").to_string(), + description = t!("schema.metadata.description").to_string(), + extend( + "readOnly" = true, + "markdownDescription" = t!("schema.metadata.markdownDescription").to_string() + ) + )] pub metadata: Option, /// The name of the registry value. #[serde(rename = "valueName", skip_serializing_if = "Option::is_none")] + #[schemars( + title = t!("schema.valueName.title").to_string(), + description = t!("schema.valueName.description").to_string(), + extend( + "markdownDescription" = t!("schema.valueName.markdownDescription").to_string() + ) + )] pub value_name: Option, /// The data of the registry value. #[serde(rename = "valueData", skip_serializing_if = "Option::is_none")] + #[schemars( + title = t!("schema.valueData.title").to_string(), + description = t!("schema.valueData.description").to_string(), + extend( + "markdownDescription" = t!("schema.valueData.markdownDescription").to_string() + ) + )] pub value_data: Option, - #[serde(rename = "_exist", skip_serializing_if = "Option::is_none")] + #[serde(rename = "_exist")] + #[schemars( + title = t!("schema.exist.title").to_string(), + description = t!("schema.exist.description").to_string(), + extend( + "default" = true, + "markdownDescription" = t!("schema.exist.markdownDescription").to_string() + ) + )] pub exist: Option, } @@ -37,5 +129,13 @@ pub struct Registry { #[serde(deny_unknown_fields)] pub struct Metadata { #[serde(rename = "whatIf", skip_serializing_if = "Option::is_none")] + #[schemars( + title = t!("schema.metadata.whatIf.title").to_string(), + description = t!("schema.metadata.whatIf.description").to_string(), + extend( + "readOnly" = true, + "markdownDescription" = t!("schema.metadata.whatIf.markdownDescription").to_string() + ) + )] pub what_if: Option> } diff --git a/registry/src/main.rs b/registry/src/main.rs index 7b078d79c..da554d433 100644 --- a/registry/src/main.rs +++ b/registry/src/main.rs @@ -6,10 +6,16 @@ use crossterm::event; #[cfg(debug_assertions)] use std::env; +#[macro_use] +extern crate rust_i18n; + +// Init translations using the `[package.metadata.i18n]` section in `Cargo.toml` +i18n!(); + use args::Arguments; use clap::Parser; use registry_helper::RegistryHelper; -use schemars::schema_for; +use schema::{canonicalize_schema, get_schema_generator}; use std::process::exit; use tracing::{debug, error}; use tracing_subscriber::{filter::LevelFilter, prelude::__tracing_subscriber_SubscriberExt, EnvFilter, Layer}; @@ -19,6 +25,7 @@ mod args; pub mod config; mod error; mod registry_helper; +mod schema; const EXIT_SUCCESS: i32 = 0; const EXIT_INVALID_INPUT: i32 = 2; @@ -111,8 +118,13 @@ fn main() { }, } }, - args::SubCommand::Schema => { - let schema = schema_for!(Registry); + args::SubCommand::Schema { enhanced } => { + let generator = get_schema_generator(enhanced); + let mut schema = generator.into_root_schema_for::(); + if !enhanced { + // Set to canonical schema URI and remove VS Code keywords + canonicalize_schema(&mut schema); + } let json =serde_json::to_string(&schema).unwrap(); println!("{json}"); }, diff --git a/registry/src/schema.rs b/registry/src/schema.rs new file mode 100644 index 000000000..988f94901 --- /dev/null +++ b/registry/src/schema.rs @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +use schemars::generate::SchemaSettings; +use schemars::transform::transform_subschemas; +use schemars::{Schema, SchemaGenerator}; +use regex::Regex; + + +/// Returns the canonical URI for the resource instance schema. +pub fn get_schema_uri(vscode: bool) -> String { + const URI_PREFIX: &str = "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/resources"; + const URI_BASE: &str = "Microsoft.Windows/Registry"; + const URI_VERSION: &str = env!("CARGO_PKG_VERSION"); + let uri_suffix = if vscode { "schema.vscode.json" } else { "schema.json" }; + + format!("{}/{}/v{}/{}", URI_PREFIX, URI_BASE, URI_VERSION, uri_suffix) +} + +/// Returns a regular expression to validate the `keyPath` resource instance property. +pub fn get_registry_key_path_pattern() -> Regex { + let prefixes: Vec = vec![ + "HKCC".to_string(), "HKEY_CURRENT_CONFIG".to_string(), + "HKCU".to_string(), "HKEY_CURRENT_USER".to_string(), + "HKCR".to_string(), "HKEY_CLASSES_ROOT".to_string(), + "HKLM".to_string(), "HKEY_LOCAL_MACHINE".to_string(), + "HKU".to_string(), "HKEY_USERS".to_string() + ]; + + Regex::new( + format!(r"^({})\\[a-zA-Z0-9-_\\]+?[^\\]$", prefixes.join("|")).as_str() + ).unwrap() +} + +/// Munges the JSON Schema to use the correct URI for the schema ID and removes VS Code keywords. +pub fn canonicalize_schema(schema: &mut Schema) { + // Update `$schema` to appropriate JSON file for 2020-12, without VS Code keywords + schema.insert("$id".to_string(), serde_json::Value::String(get_schema_uri(false))); + remove_vscode_keywords(schema); +} + +// This should more properly move to DSC for reuse +/// Recursively removes keywords from the JSON Schema that are only used and understood by VS Code +/// to provide an enhanced authoring and editing experience. The VS Code keywords are annotations +/// that most JSON Schema tools and implementations _should_ ignore, but may still cause issues. +pub fn remove_vscode_keywords(schema: &mut Schema) { + let keywords: Vec = vec![ + "defaultSnippets".to_string(), + "errorMessage".to_string(), + "patternErrorMessage".to_string(), + "deprecationMessage".to_string(), + "enumDescriptions".to_string(), + "markdownEnumDescriptions".to_string(), + "markdownDescription".to_string(), + "doNotSuggest".to_string(), + "suggestSortText".to_string(), + "allowComments".to_string(), + "allowTrailingCommas".to_string(), + ]; + for keyword in keywords { + schema.remove(&keyword); + } + + transform_subschemas(&mut remove_vscode_keywords, schema) +} + +// This should more properly move to DSC for reuse +/// Returns a `SchemaGenerator` for deriving JSON Schemas from structs. If the function is +/// called to return a generator for JSON Schemas meant for use in VS Code, it uses the +/// deprecated `definitions` keyword instead of `$defs` for references, which VS Code +/// doesn't understand yet. +pub fn get_schema_generator(for_vscode_schema: bool) -> SchemaGenerator { + let settings: SchemaSettings = if for_vscode_schema { + SchemaSettings::draft2020_12().with(|s| { + // More properly, the data should not be included in the object, instead of allowing + // or expecting null values + s.option_add_null_type = false; + // Need to use definitions instead of $defs, which VS Code doesn't understand. + s.definitions_path = "/definitions".to_string(); + }) + } else { + SchemaSettings::draft2020_12().with(|s| { + s.option_add_null_type = false; + }) + }; + settings.into_generator() +} diff --git a/schemas/resources/Microsoft.Windows/Registry/v1.0.0/schema.json b/schemas/resources/Microsoft.Windows/Registry/v1.0.0/schema.json new file mode 100644 index 000000000..aa09c027e --- /dev/null +++ b/schemas/resources/Microsoft.Windows/Registry/v1.0.0/schema.json @@ -0,0 +1,163 @@ +{ + "$id": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/resources/Microsoft.Windows/Registry/v1.0.0/schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Microsoft.Windows/Registry instance", + "description": "Manages Windows Registry keys and values.", + "type": "object", + "properties": { + "_exist": { + "title": "Exist", + "description": "Defines whether the instance should exist.", + "type": "boolean", + "default": true + }, + "_metadata": { + "title": "Resource metadata", + "description": "Defines metadata returned by the resource.", + "$ref": "#/$defs/Metadata", + "readOnly": true + }, + "keyPath": { + "title": "Registry key path", + "description": "Defines the path to the registry key to manage. Must be prefixed with a valid hive identifier. Separate the paths with back slashes only.", + "type": "string", + "pattern": "^(HKCC|HKEY_CURRENT_CONFIG|HKCU|HKEY_CURRENT_USER|HKCR|HKEY_CLASSES_ROOT|HKLM|HKEY_LOCAL_MACHINE|HKU|HKEY_USERS)\\\\[a-zA-Z0-9-_\\\\]+?[^\\\\]$" + }, + "valueData": { + "title": "Registry value data", + "description": "Defines the data for a registry value.", + "$ref": "#/$defs/RegistryValueData" + }, + "valueName": { + "title": "Registry value name", + "description": "Defines the name of the registry value to manage.", + "type": "string" + } + }, + "additionalProperties": false, + "dependentRequired": { + "valueData": [ + "valueName" + ] + }, + "required": [ + "keyPath" + ], + "$defs": { + "Metadata": { + "type": "object", + "properties": { + "whatIf": { + "title": "What-if messages", + "description": "A list of messages returned by the resource when invoked in what-if mode.", + "type": "array", + "items": { + "type": "string" + }, + "readOnly": true + } + }, + "additionalProperties": false + }, + "RegistryValueData": { + "oneOf": [ + { + "title": "String value data", + "description": "Defines the registry value as a static string.", + "type": "object", + "properties": { + "String": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "String" + ] + }, + { + "title": "Expandable string value data", + "description": "Defines the registry value as a string with expandable references.", + "type": "object", + "properties": { + "ExpandString": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "ExpandString" + ] + }, + { + "title": "Binary value data", + "description": "Defines the registry value as an array of bytes.", + "type": "object", + "properties": { + "Binary": { + "type": "array", + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0 + } + } + }, + "additionalProperties": false, + "required": [ + "Binary" + ] + }, + { + "title": "DWord value data", + "description": "Defines the registry value as an unsigned 32-bit integer.", + "type": "object", + "properties": { + "DWord": { + "type": "integer", + "format": "uint32", + "minimum": 0 + } + }, + "additionalProperties": false, + "required": [ + "DWord" + ] + }, + { + "title": "Multiple string value data", + "description": "Defines the registry value as an array of static strings.", + "type": "object", + "properties": { + "MultiString": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false, + "required": [ + "MultiString" + ] + }, + { + "title": "QWord value data", + "description": "Defines the registry value as an unsigned 64-bit integer.", + "type": "object", + "properties": { + "QWord": { + "type": "integer", + "format": "uint64", + "minimum": 0 + } + }, + "additionalProperties": false, + "required": [ + "QWord" + ] + } + ] + } + } +} diff --git a/schemas/resources/Microsoft.Windows/Registry/v1.0.0/schema.vscode.json b/schemas/resources/Microsoft.Windows/Registry/v1.0.0/schema.vscode.json new file mode 100644 index 000000000..002b6f864 --- /dev/null +++ b/schemas/resources/Microsoft.Windows/Registry/v1.0.0/schema.vscode.json @@ -0,0 +1,177 @@ +{ + "$id": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/resources/Microsoft.Windows/Registry/v1.0.0/schema.vscode.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Microsoft.Windows/Registry instance", + "description": "Manages Windows Registry keys and values.", + "type": "object", + "properties": { + "_exist": { + "title": "Exist", + "description": "Defines whether the instance should exist.", + "type": "boolean", + "default": true, + "markdownDescription": "The `_exist` property defines whether a registry key or value should exist. When this\nproperty is `true`, the resource creates the registry key or value if it doesn't exist\nduring a `set` operation. When this property is `false`, the resource deletes the registry\nkey or value if it exists during a `set` operation.\n\nThe default value is `true`." + }, + "_metadata": { + "title": "Resource metadata", + "description": "Defines metadata returned by the resource.", + "$ref": "#/definitions/Metadata", + "markdownDescription": "The `metadata` property defines metadata returned by the resource. The registry resource\ndoesn't support sending metadata input. It returns messages when invoked in what-if mode.", + "readOnly": true + }, + "keyPath": { + "title": "Registry key path", + "description": "Defines the path to the registry key to manage. Must be prefixed with a valid hive identifier. Separate the paths with back slashes only.", + "type": "string", + "markdownDescription": "The `keyPath` property defines the path to the registry key an instance\nof the resource manages. It must be prefixed with a valid hive identifier:\n\n| Identifier | Hive |\n|:-------------------------------:|:----------------------|\n| `HKCC` or `HKEY_CURRENT_CONFIG` | Current configuration |\n| `HKCU` or `HKEY_CURRENT_USER` | Current user |\n| `HKCR` or `HKEY_CLASSES_ROOT` | Classes root |\n| `HKLM` or `HKEY_LOCAL_MACHINE` | Local machine |\n| `HKU` or `HKEY_USERS` | Users |\n\nSpecify the path to the registry key with backslashes (`\\`), like\n`HKCU\\DSC\\Properties\\keyPath\\Example`. If using JSON, ensure the\nbacklsashes are escaped, like `HKCU\\\\DSC\\\\Properties\\\\keyPath\\\\Example`.", + "pattern": "^(HKCC|HKEY_CURRENT_CONFIG|HKCU|HKEY_CURRENT_USER|HKCR|HKEY_CLASSES_ROOT|HKLM|HKEY_LOCAL_MACHINE|HKU|HKEY_USERS)\\\\[a-zA-Z0-9-_\\\\]+?[^\\\\]$", + "patternErrorMessage": "The value must begin with a valid hive identifier. Valid identifiers are:\nHKCC, HKEY_CURRENT_CONFIG, HKCU, HKEY_CURRENT_USER HKCR, HKEY_CLASSES_ROOT HKLM, HKEY_LOCAL_MACHINE HKU, and HKEY_USERS." + }, + "valueData": { + "title": "Registry value data", + "description": "Defines the data for a registry value.", + "$ref": "#/definitions/RegistryValueData", + "markdownDescription": "Defines the data for a registry value. When you specify this value, you must also specify\nthe name of the registry value.\n\nDefine the data as an object with a single property. The property name determines the data\ntype and the property value determines the data value. The following table lists the\navailable data types.\n\n| Property name | Data description |\n|:--------------:|:-------------------------------------------------------------------|\n| `String` | Defines the registry value as a static string. |\n| `ExpandString` | Defines the registry value as a string with expandable references. |\n| `MultiString` | Defines the registry value as an array of static strings. |\n| `Binary` | Defines the registry value as an array of bytes. |\n| `DWord` | Defines the registry value as an unsigned 32-bit integer. |\n| `QWord` | Defines the registry value as an unsigned 64-bit integer. |" + }, + "valueName": { + "title": "Registry value name", + "description": "Defines the name of the registry value to manage.", + "type": "string", + "markdownDescription": "The `valueName` property defines the name of the registry value to manage. This value is\nrequired when specifying value data." + } + }, + "additionalProperties": false, + "dependentRequired": { + "valueData": [ + "valueName" + ] + }, + "markdownDescription": "Each instance of the `Microsoft.Windows/Registry` resource manages a registry key or value.\nYou can use it to idempotently ensure that a registry key or value exists and set the data\nfor registry values.", + "required": [ + "keyPath" + ], + "definitions": { + "Metadata": { + "type": "object", + "properties": { + "whatIf": { + "title": "What-if messages", + "description": "A list of messages returned by the resource when invoked in what-if mode.", + "type": "array", + "items": { + "type": "string" + }, + "markdownDescription": "Contains a list of messages returned by the resource when invoked in what-if mode, as with the `dsc config set --what-if` command.", + "readOnly": true + } + }, + "additionalProperties": false + }, + "RegistryValueData": { + "oneOf": [ + { + "title": "String value data", + "description": "Defines the registry value as a static string.", + "type": "object", + "properties": { + "String": { + "type": "string" + } + }, + "additionalProperties": false, + "markdownDescription": "When you define `valueData` with the `String` property, the resource sets the data for\nthe registry value as a static string. If the string contains any unexpanded references\nto environment variables, such as `%PATH%`, the references are treated as literal\ncharacters and aren't expandable.`", + "required": [ + "String" + ] + }, + { + "title": "Expandable string value data", + "description": "Defines the registry value as a string with expandable references.", + "type": "object", + "properties": { + "ExpandString": { + "type": "string" + } + }, + "additionalProperties": false, + "markdownDescription": "When you define `valueData` with the `ExpandString` property, the resource sets the data\nfor the registry value as a string. If the string contains any unexpanded references to\nenvironment variables, such as `%PATH%`, they're expandable.", + "required": [ + "ExpandString" + ] + }, + { + "title": "Binary value data", + "description": "Defines the registry value as an array of bytes.", + "type": "object", + "properties": { + "Binary": { + "type": "array", + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0 + } + } + }, + "additionalProperties": false, + "markdownDescription": "When you define `valueData` with the `Binary` property, the resource sets the data for\nthe registry value as an array of bytes. You can specify the value as an empty array or\nas an array containing the integer representation of one or more bytes.", + "required": [ + "Binary" + ] + }, + { + "title": "DWord value data", + "description": "Defines the registry value as an unsigned 32-bit integer.", + "type": "object", + "properties": { + "DWord": { + "type": "integer", + "format": "uint32", + "minimum": 0 + } + }, + "additionalProperties": false, + "markdownDescription": "When you define `valueData` with the `DWord` property, the resource sets the data for the\nregistry value as an unsigned 32-bit integer.", + "required": [ + "DWord" + ] + }, + { + "title": "Multiple string value data", + "description": "Defines the registry value as an array of static strings.", + "type": "object", + "properties": { + "MultiString": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false, + "markdownDescription": "When you define `valueData` with the `MultiString` property, the resource sets the data\nfor the registry value as an array of static strings. You can specify the value as an\nempty array, or as an array containing one or more strings. If any of the strings in the\narray contain any unexpanded references to environment variables, such as `%PATH%`, the\nreferences are treated as literal characters and aren't expandable.", + "required": [ + "MultiString" + ] + }, + { + "title": "QWord value data", + "description": "Defines the registry value as an unsigned 64-bit integer.", + "type": "object", + "properties": { + "QWord": { + "type": "integer", + "format": "uint64", + "minimum": 0 + } + }, + "additionalProperties": false, + "markdownDescription": "When you define `valueData` with the `QWord` property, the resource sets the data for the\nregistry value as an unsigned 64-bit integer.", + "required": [ + "QWord" + ] + } + ] + } + } +}